Creating Session using : alias=anon, url=http://127.0.0.1:8765, headers={}, cookies={}, auth=None, timeout=None, proxies=None, verify=False, debug=0 anon ${BASE_URL} Create Session: create a HTTP session to a server Create an unauthenticated HTTP session. ${payload} = {'master_password': 'TestPass123!', 'anime_directory': '/tmp/aniworld_test_anime', 'name': 'AniworldTest', 'data_dir': 'data', 'scheduler_enabled': 'False', 'logging_level': 'INFO', 'backup_enabled': ... ${payload} master_password=${SETUP_PASSWORD} anime_directory=/tmp/aniworld_test_anime name=AniworldTest data_dir=data scheduler_enabled=False logging_level=INFO backup_enabled=False Creates and returns a dictionary based on the given ``items``. POST Request : url=http://127.0.0.1:8765/api/auth/setup path_url=/api/auth/setup headers={'User-Agent': 'python-requests/2.33.1', 'Accept-Encoding': 'gzip, deflate, br', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Length': '208', 'Content-Type': 'application/json'} body=b'{"master_password": "TestPass123!", "anime_directory": "/tmp/aniworld_test_anime", "name": "AniworldTest", "data_dir": "data", "scheduler_enabled": "False", "logging_level": "INFO", "backup_enabled": "False"}' POST Response : url=http://127.0.0.1:8765/api/auth/setup status=400, reason=Bad Request headers={'date': 'Thu, 02 Jul 2026 19:15:17 GMT', 'server': 'uvicorn', 'content-length': '47', 'content-type': 'application/json'} body={"detail":"Master password already configured"} ${resp} = <Response [400]> ${resp} anon /api/auth/setup json=${payload} expected_status=any Sends a POST request on a previously created HTTP Session. 45s Pauses the test executed for the given time. ${resp} anon /api/auth/setup json=${payload} expected_status=any Sends a POST request on a previously created HTTP Session. 45s Pauses the test executed for the given time. ${resp} anon /api/auth/setup json=${payload} expected_status=any Sends a POST request on a previously created HTTP Session. ${json} = {'detail': 'Master password already configured'} ${json} ${resp.text} Convert String to JSON object ${detail} = ['Master password already configured'] ${detail} ${json} $.detail Get Value From JSON using JSONPath Setup failed with 400: ${detail} Fails the test with the given message and optionally alters its tags. ${resp.status_code} 201 Fails if objects are unequal after converting them to integers. Unexpected status ${resp.status_code} from /api/auth/setup Fails the test with the given message and optionally alters its tags. Configure the master password via the setup endpoint. Starting Browser process /home/lukas/miniconda3/lib/python3.13/site-packages/Browser/wrapper/index.js using at 127.0.0.1:34865 Successfully initialized new page object and opened url: http://127.0.0.1:8765/login No browser and context was open. New browser and context was automatically opened when page is created. ${BASE_URL}${path} BrowserControl Setter Open a new Page. /login Open a new page at the given path relative to BASE_URL. Fills the text 'TestPass123!' in the given field. id=password-input ${password} PageContent Setter Clears and fills the given ``txt`` into the text field found by ``selector``. Clicks the element 'id=login-submit-btn'. id=login-submit-btn PageContent Setter Simulates mouse click on the element found by ``selector``. Waited for Element with selector id=search-input at state visible id=search-input visible timeout=5s PageContent Wait Waits for the element found by ``selector`` to satisfy state option. Fill the login form and submit it. Waited for Element with selector id=search-input at state visible id=search-input visible timeout=5s PageContent Wait Waits for the element found by ``selector`` to satisfy state option. ${payload} = {'password': 'TestPass123!'} ${payload} password=${SETUP_PASSWORD} Creates and returns a dictionary based on the given ``items``. POST Request : url=http://127.0.0.1:8765/api/auth/login path_url=/api/auth/login headers={'User-Agent': 'python-requests/2.33.1', 'Accept-Encoding': 'gzip, deflate, br', 'Accept': '*/*', 'Connection': 'keep-alive', 'Content-Length': '28', 'Content-Type': 'application/json'} body=b'{"password": "TestPass123!"}' POST Response : url=http://127.0.0.1:8765/api/auth/login status=200, reason=OK headers={'date': 'Thu, 02 Jul 2026 19:15:19 GMT', 'server': 'uvicorn', 'content-length': '232', 'content-type': 'application/json'} body={"access_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtYXN0ZXIiLCJleHAiOjE3ODMxMDYxMjAsImlhdCI6MTc4MzAxOTcyMH0.3lTBRZRfwrf3WmkoccB95LHtGASRwoG4SUqCpIwCehU","token_type":"bearer","expires_at":"2026-07-03T19:15:20.295776Z"} ${resp} = <Response [200]> ${resp} anon /api/auth/login json=${payload} expected_status=any Sends a POST request on a previously created HTTP Session. 6s Pauses the test executed for the given time. ${resp} anon /api/auth/login json=${payload} expected_status=any Sends a POST request on a previously created HTTP Session. ${json} ${resp.text} Convert String to JSON object ${detail} ${json} $.detail Get Value From JSON using JSONPath ${detail_val} ${detail}[0] Returns the given values which can then be assigned to a variables. Login failed with ${resp.status_code}: ${detail_val} Fails the test with the given message and optionally alters its tags. ${json} = {'access_token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtYXN0ZXIiLCJleHAiOjE3ODMxMDYxMjAsImlhdCI6MTc4MzAxOTcyMH0.3lTBRZRfwrf3WmkoccB95LHtGASRwoG4SUqCpIwCehU', 'token_type': 'bearer', 'expire... ${json} ${resp.text} Convert String to JSON object ${token} = ['eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtYXN0ZXIiLCJleHAiOjE3ODMxMDYxMjAsImlhdCI6MTc4MzAxOTcyMH0.3lTBRZRfwrf3WmkoccB95LHtGASRwoG4SUqCpIwCehU'] ${token} ${json} $.access_token Get Value From JSON using JSONPath ${token_str} = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtYXN0ZXIiLCJleHAiOjE3ODMxMDYxMjAsImlhdCI6MTc4MzAxOTcyMH0.3lTBRZRfwrf3WmkoccB95LHtGASRwoG4SUqCpIwCehU ${token_str} ${token}[0] Returns the given values which can then be assigned to a variables. ${TOKEN} = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtYXN0ZXIiLCJleHAiOjE3ODMxMDYxMjAsImlhdCI6MTc4MzAxOTcyMH0.3lTBRZRfwrf3WmkoccB95LHtGASRwoG4SUqCpIwCehU ${TOKEN} ${token_str} Makes a variable available everywhere within the scope of the current suite. ${token_str} Log in with the master password and return the JWT access token. Creating Session using : alias=auth, url=http://127.0.0.1:8765, headers={'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtYXN0ZXIiLCJleHAiOjE3ODMxMDYxMjAsImlhdCI6MTc4MzAxOTcyMH0.3lTBRZRfwrf3WmkoccB95LHtGASRwoG4SUqCpIwCehU'}, cookies={}, auth=None, timeout=None, proxies=None, verify=False, debug=0 auth ${BASE_URL} headers={'Authorization': 'Bearer ${TOKEN}'} Create Session: create a HTTP session to a server Create Anonymous Session AND Setup Master Password AND Open Browser To Page /login AND Perform Login AND Wait For Elements State id=search-input visible timeout=5s AND Login And Get Token AND Create Session auth ${BASE_URL} headers={'Authorization': 'Bearer ${TOKEN}'} Executes all the given keywords in a sequence. ${payload} = {'link': 'https://aniworld.to/anime/stream/attack-on-titan', 'name': 'Attack on Titan'} ${payload} link=${link} name=${name} Creates and returns a dictionary based on the given ``items``. ${payload} year=${year} Adds the given ``key_value_pairs`` and/or ``items`` to the ``dictionary``. ${resp} ${session} ${endpoint} expected_status=${expected_status} Sends a POST request on a previously created HTTP Session. POST Request : url=http://127.0.0.1:8765/api/anime/add path_url=/api/anime/add headers={'User-Agent': 'python-requests/2.33.1', 'Accept-Encoding': 'gzip, deflate, br', 'Accept': '*/*', 'Connection': 'keep-alive', 'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtYXN0ZXIiLCJleHAiOjE3ODMxMDYxMjAsImlhdCI6MTc4MzAxOTcyMH0.3lTBRZRfwrf3WmkoccB95LHtGASRwoG4SUqCpIwCehU', 'Content-Length': '103', 'Content-Type': 'application/json'} body=b'{"link": "https://aniworld.to/anime/stream/attack-on-titan", "name": "Attack on Titan", "year": "2013"}' POST Response : url=http://127.0.0.1:8765/api/anime/add status=202, reason=Accepted headers={'date': 'Thu, 02 Jul 2026 19:15:19 GMT', 'server': 'uvicorn', 'content-length': '243', 'content-type': 'application/json'} body={"status":"exists","message":"Series already exists: Attack on Titan","key":"attack-on-titan","folder":"Attack on Titan (2013)","db_id":1,"loading_status":"completed","loading_progress":{"episodes":true,"nfo":true,"logo":false,"images":false}} ${resp} = <Response [202]> ${resp} ${session} ${endpoint} json=${payload} expected_status=${expected_status} Sends a POST request on a previously created HTTP Session. ${resp} ${resp} = <Response [202]> ${resp} /api/anime/add ${payload} 202 Perform an authenticated POST request with optional JSON payload. ${resp} ${resp} = <Response [202]> ${resp} https://aniworld.to/anime/stream/attack-on-titan Attack on Titan 2013 POST /api/anime/add with series details. Argument types are: <class 'int'> <class 'str'> ${response.status_code} ${expected_status} Fails if objects are unequal after converting them to integers. ${resp} 202 Assert that the response status code matches the expected value. ${json} = {'status': 'exists', 'message': 'Series already exists: Attack on Titan', 'key': 'attack-on-titan', 'folder': 'Attack on Titan (2013)', 'db_id': 1, 'loading_status': 'completed', 'loading_progress': {... ${json} ${response.text} Convert String to JSON object ${values} = ['attack-on-titan'] ${values} ${json} ${json_path} Get Value From JSON using JSONPath ${value} = attack-on-titan ${value} ${values}[0] Returns the given values which can then be assigned to a variables. ${value} ${key} = attack-on-titan ${key} ${resp} $.key Extract a value from a JSON response using JSONPath. Length is 15. ${key} Verifies that the given item is not empty. Successfully opened URL http://127.0.0.1:8765/anime/settings?key=attack-on-titan ${BASE_URL}/anime/settings?key=${key} BrowserControl Setter Navigates to the given ``url``. </td></tr><tr><td colspan="3"><a href="browser/screenshot/fail-screenshot-1.png" target="_blank"><img src="browser/screenshot/fail-screenshot-1.png" width="800px"/></a> See also file:///home/lukas/Volume/repo/Aniworld/playwright-log.txt for additional details. Error: locator.evaluate: Unexpected token "&" while parsing css selector "window.AniWorld && window.AniWorld.AnimeSettingsManager && window.AniWorld.AnimeSettingsManager.init()". Did you mean to CSS.escape it? Call log: - waiting for window.AniWorld && window.AniWorld.AnimeSettingsManager && window.AniWorld.AnimeSettingsManager.init() window.AniWorld && window.AniWorld.AnimeSettingsManager && window.AniWorld.AnimeSettingsManager.init() Getter PageContent Setter Executes given javascript on the selected element(s) or on page. Error: locator.evaluate: Unexpected token "&" while parsing css selector "window.AniWorld && window.AniWorld.AnimeSettingsManager && window.AniWorld.AnimeSettingsManager.init()". Did you mean to CSS.escape it? Call log: - waiting for window.AniWorld && window.AniWorld.AnimeSettingsManager && window.AniWorld.AnimeSettingsManager.init() id=settings-section visible timeout=10s PageContent Wait Waits for the element found by ``selector`` to satisfy state option. Settings Assert that the page title contains the given text. id=settings-section Assert that the element matching the selector is visible. id=regenerate-nfo-btn Assert that the element matching the selector is visible. id=save-db-btn Assert that the element matching the selector is visible. Closed all browsers ALL BrowserControl Setter Closes the current browser. Close all browser contexts and the browser itself. Navigate to anime settings page and verify form elements. Error: locator.evaluate: Unexpected token "&" while parsing css selector "window.AniWorld && window.AniWorld.AnimeSettingsManager && window.AniWorld.AnimeSettingsManager.init()". Did you mean to CSS.escape it? Call log: - waiting for window.AniWorld && window.AniWorld.AnimeSettingsManager && window.AniWorld.AnimeSettingsManager.init() Anime settings page UI tests for Aniworld. Covers page load, regenerate NFO, and update series settings. All Tests Anime Settings