Files
Aniworld/robot_output/output.xml
Lukas d940460355 Cleanup obsolete tasks, simplify auth lock logic, increase test retry wait
- Remove completed Task 17 and 18 from Docs/tasks.md
- Remove ANIWORLD_TESTING bypass in _check_locked (testing env now uses test auth service)
- Remove redundant lock expiry cleanup (handled by _get_fail_record)
- Fix login.html whitespace formatting
- Increase setup retry wait from 6s to 45s for rate-limited CI environments
2026-06-26 21:04:45 +02:00

1680 lines
78 KiB
XML

<?xml version="1.0" encoding="UTF-8"?>
<robot generator="Robot 7.4.2 (Python 3.13.5 on linux)" generated="2026-06-26T21:00:40.600072" rpa="false" schemaversion="5">
<suite id="s1" name="Login" source="/home/lukas/Volume/repo/Aniworld/tests/robot/ui/login.robot">
<test id="s1-t1" name="Login Page Loads" line="18">
<kw name="Run Keywords" owner="BuiltIn" type="SETUP">
<kw name="Create Anonymous Session" owner="common">
<kw name="Create Session" owner="RequestsLibrary">
<msg time="2026-06-26T21:00:40.814324" level="INFO">Creating Session using : alias=anon, url=http://127.0.0.1:8765, headers={}, cookies={}, auth=None, timeout=None, proxies=None, verify=False, debug=0 </msg>
<arg>anon</arg>
<arg>${BASE_URL}</arg>
<doc>Create Session: create a HTTP session to a server</doc>
<status status="PASS" start="2026-06-26T21:00:40.814151" elapsed="0.000325"/>
</kw>
<doc>Create an unauthenticated HTTP session.</doc>
<status status="PASS" start="2026-06-26T21:00:40.813916" elapsed="0.000637"/>
</kw>
<kw name="Setup Master Password" owner="common">
<kw name="Create Dictionary" owner="BuiltIn">
<msg time="2026-06-26T21:00:40.815395" level="INFO">${payload} = {'master_password': 'TestPass123!', 'anime_directory': '/tmp/aniworld_test_anime', 'name': 'AniworldTest', 'data_dir': 'data', 'scheduler_enabled': 'False', 'logging_level': 'INFO', 'backup_enabled': ...</msg>
<var>${payload}</var>
<arg>master_password=${SETUP_PASSWORD}</arg>
<arg>anime_directory=/tmp/aniworld_test_anime</arg>
<arg>name=AniworldTest</arg>
<arg>data_dir=data</arg>
<arg>scheduler_enabled=False</arg>
<arg>logging_level=INFO</arg>
<arg>backup_enabled=False</arg>
<doc>Creates and returns a dictionary based on the given ``items``.</doc>
<status status="PASS" start="2026-06-26T21:00:40.815012" elapsed="0.000411"/>
</kw>
<kw name="POST On Session" owner="RequestsLibrary">
<msg time="2026-06-26T21:00:40.817588" level="INFO">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"}'
</msg>
<msg time="2026-06-26T21:00:40.817655" level="INFO">POST Response : url=http://127.0.0.1:8765/api/auth/setup
status=429, reason=Too Many Requests
headers={'date': 'Fri, 26 Jun 2026 19:00:40 GMT', 'server': 'uvicorn', 'content-length': '74', 'content-type': 'application/json'}
body={"detail":"Too many authentication attempts, try again later. IP lockout"}
</msg>
<msg time="2026-06-26T21:00:40.817747" level="INFO">${resp} = &lt;Response [429]&gt;</msg>
<var>${resp}</var>
<arg>anon</arg>
<arg>/api/auth/setup</arg>
<arg>json=${payload}</arg>
<arg>expected_status=any</arg>
<doc>Sends a POST request on a previously created HTTP Session.</doc>
<status status="PASS" start="2026-06-26T21:00:40.815520" elapsed="0.002249"/>
</kw>
<if>
<branch type="IF" condition="'${resp.status_code}' == '429'">
<kw name="Sleep" owner="BuiltIn">
<msg time="2026-06-26T21:01:25.818635" level="INFO">Slept 45 seconds.</msg>
<arg>45s</arg>
<doc>Pauses the test executed for the given time.</doc>
<status status="PASS" start="2026-06-26T21:00:40.818286" elapsed="45.000457"/>
</kw>
<kw name="POST On Session" owner="RequestsLibrary">
<msg time="2026-06-26T21:01:25.821519" level="INFO">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"}'
</msg>
<msg time="2026-06-26T21:01:25.821580" level="INFO">POST Response : url=http://127.0.0.1:8765/api/auth/setup
status=400, reason=Bad Request
headers={'date': 'Fri, 26 Jun 2026 19:01:25 GMT', 'server': 'uvicorn', 'content-length': '47', 'content-type': 'application/json'}
body={"detail":"Master password already configured"}
</msg>
<msg time="2026-06-26T21:01:25.821689" level="INFO">${resp} = &lt;Response [400]&gt;</msg>
<var>${resp}</var>
<arg>anon</arg>
<arg>/api/auth/setup</arg>
<arg>json=${payload}</arg>
<arg>expected_status=any</arg>
<doc>Sends a POST request on a previously created HTTP Session.</doc>
<status status="PASS" start="2026-06-26T21:01:25.818900" elapsed="0.002810"/>
</kw>
<status status="PASS" start="2026-06-26T21:00:40.817870" elapsed="45.003901"/>
</branch>
<status status="PASS" start="2026-06-26T21:00:40.817849" elapsed="45.003966"/>
</if>
<if>
<branch type="IF" condition="'${resp.status_code}' == '429'">
<kw name="Sleep" owner="BuiltIn">
<arg>45s</arg>
<doc>Pauses the test executed for the given time.</doc>
<status status="NOT RUN" start="2026-06-26T21:01:25.822413" elapsed="0.000057"/>
</kw>
<kw name="POST On Session" owner="RequestsLibrary">
<var>${resp}</var>
<arg>anon</arg>
<arg>/api/auth/setup</arg>
<arg>json=${payload}</arg>
<arg>expected_status=any</arg>
<doc>Sends a POST request on a previously created HTTP Session.</doc>
<status status="NOT RUN" start="2026-06-26T21:01:25.822554" elapsed="0.000045"/>
</kw>
<status status="NOT RUN" start="2026-06-26T21:01:25.821879" elapsed="0.000757"/>
</branch>
<status status="PASS" start="2026-06-26T21:01:25.821859" elapsed="0.000808"/>
</if>
<if>
<branch type="IF" condition="'${resp.status_code}' == '400'">
<kw name="Convert String To Json" owner="JSONLibrary">
<msg time="2026-06-26T21:01:25.823440" level="INFO">${json} = {'detail': 'Master password already configured'}</msg>
<var>${json}</var>
<arg>${resp.text}</arg>
<doc>Convert String to JSON object</doc>
<status status="PASS" start="2026-06-26T21:01:25.823083" elapsed="0.000381"/>
</kw>
<kw name="Get Value From Json" owner="JSONLibrary">
<msg time="2026-06-26T21:01:25.836407" level="INFO">${detail} = ['Master password already configured']</msg>
<var>${detail}</var>
<arg>${json}</arg>
<arg>$.detail</arg>
<doc>Get Value From JSON using JSONPath</doc>
<status status="PASS" start="2026-06-26T21:01:25.823548" elapsed="0.012899"/>
</kw>
<if>
<branch type="IF" condition="'${detail}[0]' == 'Master password already configured'">
<return>
<status status="PASS" start="2026-06-26T21:01:25.836838" elapsed="0.000080"/>
</return>
<status status="PASS" start="2026-06-26T21:01:25.836550" elapsed="0.000411"/>
</branch>
<status status="PASS" start="2026-06-26T21:01:25.836531" elapsed="0.000460"/>
</if>
<kw name="Fail" owner="BuiltIn">
<arg>Setup failed with 400: ${detail}</arg>
<doc>Fails the test with the given message and optionally alters its tags.</doc>
<status status="NOT RUN" start="2026-06-26T21:01:25.837087" elapsed="0.000055"/>
</kw>
<status status="PASS" start="2026-06-26T21:01:25.822716" elapsed="0.014460"/>
</branch>
<status status="PASS" start="2026-06-26T21:01:25.822703" elapsed="0.014500"/>
</if>
<if>
<branch type="IF" condition="'${resp.status_code}' == '201'">
<kw name="Should Be Equal As Integers" owner="BuiltIn">
<arg>${resp.status_code}</arg>
<arg>201</arg>
<doc>Fails if objects are unequal after converting them to integers.</doc>
<status status="NOT RUN" start="2026-06-26T21:01:25.837342" elapsed="0.000043"/>
</kw>
<return>
<status status="NOT RUN" start="2026-06-26T21:01:25.837423" elapsed="0.000038"/>
</return>
<status status="NOT RUN" start="2026-06-26T21:01:25.837245" elapsed="0.000241"/>
</branch>
<status status="NOT RUN" start="2026-06-26T21:01:25.837233" elapsed="0.000275"/>
</if>
<kw name="Fail" owner="BuiltIn">
<arg>Unexpected status ${resp.status_code} from /api/auth/setup</arg>
<doc>Fails the test with the given message and optionally alters its tags.</doc>
<status status="NOT RUN" start="2026-06-26T21:01:25.837575" elapsed="0.000054"/>
</kw>
<doc>Configure the master password via the setup endpoint.</doc>
<status status="PASS" start="2026-06-26T21:00:40.814798" elapsed="45.022908"/>
</kw>
<arg>Create Anonymous Session</arg>
<arg>AND</arg>
<arg>Setup Master Password</arg>
<doc>Executes all the given keywords in a sequence.</doc>
<status status="PASS" start="2026-06-26T21:00:40.813426" elapsed="45.024483"/>
</kw>
<kw name="Open Browser To Page" owner="common">
<kw name="New Page" owner="Browser">
<msg time="2026-06-26T21:01:25.842728" level="INFO">Starting Browser process /home/lukas/miniconda3/lib/python3.13/site-packages/Browser/wrapper/index.js using at 127.0.0.1:40597</msg>
<msg time="2026-06-26T21:01:26.652943" level="INFO">Successfully initialized new page object and opened url: http://127.0.0.1:8765/login</msg>
<msg time="2026-06-26T21:01:26.653006" level="INFO">No browser and context was open. New browser and context was automatically opened when page is created.</msg>
<arg>${BASE_URL}${path}</arg>
<tag>BrowserControl</tag>
<tag>Setter</tag>
<doc>Open a new Page.</doc>
<status status="PASS" start="2026-06-26T21:01:25.838440" elapsed="0.814700"/>
</kw>
<arg>/login</arg>
<doc>Open a new page at the given path relative to BASE_URL.</doc>
<status status="PASS" start="2026-06-26T21:01:25.838102" elapsed="0.815145"/>
</kw>
<kw name="Page Title Should Contain" owner="ui_keywords">
<kw name="Get Title" owner="Browser">
<msg time="2026-06-26T21:01:26.660636" level="INFO">Title: 'AniWorld Manager - Login'</msg>
<msg time="2026-06-26T21:01:26.660778" level="INFO">${title} = AniWorld Manager - Login</msg>
<var>${title}</var>
<tag>Assertion</tag>
<tag>Getter</tag>
<tag>PageContent</tag>
<doc>Returns the title of the current page.</doc>
<status status="PASS" start="2026-06-26T21:01:26.653770" elapsed="0.007031"/>
</kw>
<kw name="Should Contain" owner="BuiltIn">
<arg>${title}</arg>
<arg>${text}</arg>
<doc>Fails if ``container`` does not contain ``item`` one or more times.</doc>
<status status="PASS" start="2026-06-26T21:01:26.660960" elapsed="0.000559"/>
</kw>
<arg>Login</arg>
<doc>Assert that the page title contains the given text.</doc>
<status status="PASS" start="2026-06-26T21:01:26.653409" elapsed="0.008182"/>
</kw>
<kw name="Element Should Be Visible" owner="ui_keywords">
<kw name="Wait For Elements State" owner="Browser">
<msg time="2026-06-26T21:01:26.683394" level="INFO">Waited for Element with selector id=password-input at state visible</msg>
<arg>${selector}</arg>
<arg>visible</arg>
<arg>timeout=5s</arg>
<tag>PageContent</tag>
<tag>Wait</tag>
<doc>Waits for the element found by ``selector`` to satisfy state option.</doc>
<status status="PASS" start="2026-06-26T21:01:26.662003" elapsed="0.021532"/>
</kw>
<arg>id=password-input</arg>
<doc>Assert that the element matching the selector is visible.</doc>
<status status="PASS" start="2026-06-26T21:01:26.661724" elapsed="0.021905"/>
</kw>
<kw name="Element Should Be Visible" owner="ui_keywords">
<kw name="Wait For Elements State" owner="Browser">
<msg time="2026-06-26T21:01:26.690216" level="INFO">Waited for Element with selector id=login-submit-btn at state visible</msg>
<arg>${selector}</arg>
<arg>visible</arg>
<arg>timeout=5s</arg>
<tag>PageContent</tag>
<tag>Wait</tag>
<doc>Waits for the element found by ``selector`` to satisfy state option.</doc>
<status status="PASS" start="2026-06-26T21:01:26.684160" elapsed="0.006190"/>
</kw>
<arg>id=login-submit-btn</arg>
<doc>Assert that the element matching the selector is visible.</doc>
<status status="PASS" start="2026-06-26T21:01:26.683806" elapsed="0.006634"/>
</kw>
<kw name="Element Should Be Visible" owner="ui_keywords">
<kw name="Wait For Elements State" owner="Browser">
<msg time="2026-06-26T21:01:26.696018" level="INFO">Waited for Element with selector id=password-toggle at state visible</msg>
<arg>${selector}</arg>
<arg>visible</arg>
<arg>timeout=5s</arg>
<tag>PageContent</tag>
<tag>Wait</tag>
<doc>Waits for the element found by ``selector`` to satisfy state option.</doc>
<status status="PASS" start="2026-06-26T21:01:26.690933" elapsed="0.005204"/>
</kw>
<arg>id=password-toggle</arg>
<doc>Assert that the element matching the selector is visible.</doc>
<status status="PASS" start="2026-06-26T21:01:26.690591" elapsed="0.005632"/>
</kw>
<kw name="Close Browser" owner="common" type="TEARDOWN">
<kw name="Close Browser" owner="Browser">
<msg time="2026-06-26T21:01:26.717808" level="INFO">Closed all browsers</msg>
<arg>ALL</arg>
<tag>BrowserControl</tag>
<tag>Setter</tag>
<doc>Closes the current browser.</doc>
<status status="PASS" start="2026-06-26T21:01:26.696733" elapsed="0.021216"/>
</kw>
<doc>Close all browser contexts and the browser itself.</doc>
<status status="PASS" start="2026-06-26T21:01:26.696425" elapsed="0.021616"/>
</kw>
<doc>Verify the login page loads with all form elements.</doc>
<status status="PASS" start="2026-06-26T21:00:40.812555" elapsed="45.905530"/>
</test>
<test id="s1-t2" name="Login With Valid Password" line="29">
<kw name="Run Keywords" owner="BuiltIn" type="SETUP">
<kw name="Create Anonymous Session" owner="common">
<kw name="Create Session" owner="RequestsLibrary">
<msg time="2026-06-26T21:01:26.728162" level="INFO">Creating Session using : alias=anon, url=http://127.0.0.1:8765, headers={}, cookies={}, auth=None, timeout=None, proxies=None, verify=False, debug=0 </msg>
<arg>anon</arg>
<arg>${BASE_URL}</arg>
<doc>Create Session: create a HTTP session to a server</doc>
<status status="PASS" start="2026-06-26T21:01:26.728022" elapsed="0.000261"/>
</kw>
<doc>Create an unauthenticated HTTP session.</doc>
<status status="PASS" start="2026-06-26T21:01:26.727796" elapsed="0.000549"/>
</kw>
<kw name="Setup Master Password" owner="common">
<kw name="Create Dictionary" owner="BuiltIn">
<msg time="2026-06-26T21:01:26.729118" level="INFO">${payload} = {'master_password': 'TestPass123!', 'anime_directory': '/tmp/aniworld_test_anime', 'name': 'AniworldTest', 'data_dir': 'data', 'scheduler_enabled': 'False', 'logging_level': 'INFO', 'backup_enabled': ...</msg>
<var>${payload}</var>
<arg>master_password=${SETUP_PASSWORD}</arg>
<arg>anime_directory=/tmp/aniworld_test_anime</arg>
<arg>name=AniworldTest</arg>
<arg>data_dir=data</arg>
<arg>scheduler_enabled=False</arg>
<arg>logging_level=INFO</arg>
<arg>backup_enabled=False</arg>
<doc>Creates and returns a dictionary based on the given ``items``.</doc>
<status status="PASS" start="2026-06-26T21:01:26.728789" elapsed="0.000354"/>
</kw>
<kw name="POST On Session" owner="RequestsLibrary">
<msg time="2026-06-26T21:01:26.731060" level="INFO">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"}'
</msg>
<msg time="2026-06-26T21:01:26.731107" level="INFO">POST Response : url=http://127.0.0.1:8765/api/auth/setup
status=400, reason=Bad Request
headers={'date': 'Fri, 26 Jun 2026 19:01:26 GMT', 'server': 'uvicorn', 'content-length': '47', 'content-type': 'application/json'}
body={"detail":"Master password already configured"}
</msg>
<msg time="2026-06-26T21:01:26.731178" level="INFO">${resp} = &lt;Response [400]&gt;</msg>
<var>${resp}</var>
<arg>anon</arg>
<arg>/api/auth/setup</arg>
<arg>json=${payload}</arg>
<arg>expected_status=any</arg>
<doc>Sends a POST request on a previously created HTTP Session.</doc>
<status status="PASS" start="2026-06-26T21:01:26.729239" elapsed="0.001958"/>
</kw>
<if>
<branch type="IF" condition="'${resp.status_code}' == '429'">
<kw name="Sleep" owner="BuiltIn">
<arg>45s</arg>
<doc>Pauses the test executed for the given time.</doc>
<status status="NOT RUN" start="2026-06-26T21:01:26.731751" elapsed="0.000094"/>
</kw>
<kw name="POST On Session" owner="RequestsLibrary">
<var>${resp}</var>
<arg>anon</arg>
<arg>/api/auth/setup</arg>
<arg>json=${payload}</arg>
<arg>expected_status=any</arg>
<doc>Sends a POST request on a previously created HTTP Session.</doc>
<status status="NOT RUN" start="2026-06-26T21:01:26.731932" elapsed="0.000093"/>
</kw>
<status status="NOT RUN" start="2026-06-26T21:01:26.731277" elapsed="0.000896"/>
</branch>
<status status="PASS" start="2026-06-26T21:01:26.731257" elapsed="0.000949"/>
</if>
<if>
<branch type="IF" condition="'${resp.status_code}' == '429'">
<kw name="Sleep" owner="BuiltIn">
<arg>45s</arg>
<doc>Pauses the test executed for the given time.</doc>
<status status="NOT RUN" start="2026-06-26T21:01:26.732622" elapsed="0.000047"/>
</kw>
<kw name="POST On Session" owner="RequestsLibrary">
<var>${resp}</var>
<arg>anon</arg>
<arg>/api/auth/setup</arg>
<arg>json=${payload}</arg>
<arg>expected_status=any</arg>
<doc>Sends a POST request on a previously created HTTP Session.</doc>
<status status="NOT RUN" start="2026-06-26T21:01:26.732754" elapsed="0.000079"/>
</kw>
<status status="NOT RUN" start="2026-06-26T21:01:26.732250" elapsed="0.000618"/>
</branch>
<status status="PASS" start="2026-06-26T21:01:26.732237" elapsed="0.000659"/>
</if>
<if>
<branch type="IF" condition="'${resp.status_code}' == '400'">
<kw name="Convert String To Json" owner="JSONLibrary">
<msg time="2026-06-26T21:01:26.733669" level="INFO">${json} = {'detail': 'Master password already configured'}</msg>
<var>${json}</var>
<arg>${resp.text}</arg>
<doc>Convert String to JSON object</doc>
<status status="PASS" start="2026-06-26T21:01:26.733336" elapsed="0.000362"/>
</kw>
<kw name="Get Value From Json" owner="JSONLibrary">
<msg time="2026-06-26T21:01:26.744527" level="INFO">${detail} = ['Master password already configured']</msg>
<var>${detail}</var>
<arg>${json}</arg>
<arg>$.detail</arg>
<doc>Get Value From JSON using JSONPath</doc>
<status status="PASS" start="2026-06-26T21:01:26.733804" elapsed="0.010755"/>
</kw>
<if>
<branch type="IF" condition="'${detail}[0]' == 'Master password already configured'">
<return>
<status status="PASS" start="2026-06-26T21:01:26.744863" elapsed="0.000068"/>
</return>
<status status="PASS" start="2026-06-26T21:01:26.744644" elapsed="0.000326"/>
</branch>
<status status="PASS" start="2026-06-26T21:01:26.744626" elapsed="0.000372"/>
</if>
<kw name="Fail" owner="BuiltIn">
<arg>Setup failed with 400: ${detail}</arg>
<doc>Fails the test with the given message and optionally alters its tags.</doc>
<status status="NOT RUN" start="2026-06-26T21:01:26.745088" elapsed="0.000051"/>
</kw>
<status status="PASS" start="2026-06-26T21:01:26.732934" elapsed="0.012240"/>
</branch>
<status status="PASS" start="2026-06-26T21:01:26.732923" elapsed="0.012277"/>
</if>
<if>
<branch type="IF" condition="'${resp.status_code}' == '201'">
<kw name="Should Be Equal As Integers" owner="BuiltIn">
<arg>${resp.status_code}</arg>
<arg>201</arg>
<doc>Fails if objects are unequal after converting them to integers.</doc>
<status status="NOT RUN" start="2026-06-26T21:01:26.745337" elapsed="0.000041"/>
</kw>
<return>
<status status="NOT RUN" start="2026-06-26T21:01:26.745415" elapsed="0.000036"/>
</return>
<status status="NOT RUN" start="2026-06-26T21:01:26.745240" elapsed="0.000235"/>
</branch>
<status status="NOT RUN" start="2026-06-26T21:01:26.745229" elapsed="0.000267"/>
</if>
<kw name="Fail" owner="BuiltIn">
<arg>Unexpected status ${resp.status_code} from /api/auth/setup</arg>
<doc>Fails the test with the given message and optionally alters its tags.</doc>
<status status="NOT RUN" start="2026-06-26T21:01:26.745550" elapsed="0.000038"/>
</kw>
<doc>Configure the master password via the setup endpoint.</doc>
<status status="PASS" start="2026-06-26T21:01:26.728557" elapsed="0.017084"/>
</kw>
<arg>Create Anonymous Session</arg>
<arg>AND</arg>
<arg>Setup Master Password</arg>
<doc>Executes all the given keywords in a sequence.</doc>
<status status="PASS" start="2026-06-26T21:01:26.727340" elapsed="0.018339"/>
</kw>
<kw name="Open Browser To Page" owner="common">
<kw name="New Page" owner="Browser">
<msg time="2026-06-26T21:01:27.136030" level="INFO">Successfully initialized new page object and opened url: http://127.0.0.1:8765/login</msg>
<msg time="2026-06-26T21:01:27.136091" level="INFO">No browser and context was open. New browser and context was automatically opened when page is created.</msg>
<arg>${BASE_URL}${path}</arg>
<tag>BrowserControl</tag>
<tag>Setter</tag>
<doc>Open a new Page.</doc>
<status status="PASS" start="2026-06-26T21:01:26.746050" elapsed="0.390160"/>
</kw>
<arg>/login</arg>
<doc>Open a new page at the given path relative to BASE_URL.</doc>
<status status="PASS" start="2026-06-26T21:01:26.745810" elapsed="0.390487"/>
</kw>
<kw name="Perform Login" owner="ui_keywords">
<kw name="Fill Text" owner="Browser">
<msg time="2026-06-26T21:01:27.137293" level="INFO">Fills the text 'TestPass123!' in the given field.</msg>
<arg>id=password-input</arg>
<arg>${password}</arg>
<tag>PageContent</tag>
<tag>Setter</tag>
<doc>Clears and fills the given ``txt`` into the text field found by ``selector``.</doc>
<status status="PASS" start="2026-06-26T21:01:27.136884" elapsed="0.025260"/>
</kw>
<kw name="Click" owner="Browser">
<msg time="2026-06-26T21:01:27.162730" level="INFO">Clicks the element 'id=login-submit-btn'.</msg>
<arg>id=login-submit-btn</arg>
<tag>PageContent</tag>
<tag>Setter</tag>
<doc>Simulates mouse click on the element found by ``selector``.</doc>
<status status="PASS" start="2026-06-26T21:01:27.162317" elapsed="0.034434"/>
</kw>
<kw name="Wait For Elements State" owner="Browser">
<msg time="2026-06-26T21:01:28.491647" level="INFO">Waited for Element with selector id=search-input at state visible</msg>
<arg>id=search-input</arg>
<arg>visible</arg>
<arg>timeout=5s</arg>
<tag>PageContent</tag>
<tag>Wait</tag>
<doc>Waits for the element found by ``selector`` to satisfy state option.</doc>
<status status="PASS" start="2026-06-26T21:01:27.196925" elapsed="1.294947"/>
</kw>
<arg>${SETUP_PASSWORD}</arg>
<doc>Fill the login form and submit it.</doc>
<status status="PASS" start="2026-06-26T21:01:27.136450" elapsed="1.355549"/>
</kw>
<kw name="Page Title Should Contain" owner="ui_keywords">
<kw name="Get Title" owner="Browser">
<msg time="2026-06-26T21:01:28.495741" level="INFO">Title: 'AniWorld Manager'</msg>
<msg time="2026-06-26T21:01:28.495861" level="INFO">${title} = AniWorld Manager</msg>
<var>${title}</var>
<tag>Assertion</tag>
<tag>Getter</tag>
<tag>PageContent</tag>
<doc>Returns the title of the current page.</doc>
<status status="PASS" start="2026-06-26T21:01:28.492732" elapsed="0.003149"/>
</kw>
<kw name="Should Contain" owner="BuiltIn">
<arg>${title}</arg>
<arg>${text}</arg>
<doc>Fails if ``container`` does not contain ``item`` one or more times.</doc>
<status status="PASS" start="2026-06-26T21:01:28.496029" elapsed="0.000398"/>
</kw>
<arg>AniWorld</arg>
<doc>Assert that the page title contains the given text.</doc>
<status status="PASS" start="2026-06-26T21:01:28.492216" elapsed="0.004275"/>
</kw>
<kw name="Element Should Be Visible" owner="ui_keywords">
<kw name="Wait For Elements State" owner="Browser">
<msg time="2026-06-26T21:01:28.501119" level="INFO">Waited for Element with selector id=search-input at state visible</msg>
<arg>${selector}</arg>
<arg>visible</arg>
<arg>timeout=5s</arg>
<tag>PageContent</tag>
<tag>Wait</tag>
<doc>Waits for the element found by ``selector`` to satisfy state option.</doc>
<status status="PASS" start="2026-06-26T21:01:28.496897" elapsed="0.004417"/>
</kw>
<arg>id=search-input</arg>
<doc>Assert that the element matching the selector is visible.</doc>
<status status="PASS" start="2026-06-26T21:01:28.496609" elapsed="0.004841"/>
</kw>
<kw name="Close Browser" owner="common" type="TEARDOWN">
<kw name="Close Browser" owner="Browser">
<msg time="2026-06-26T21:01:28.522061" level="INFO">Closed all browsers</msg>
<arg>ALL</arg>
<tag>BrowserControl</tag>
<tag>Setter</tag>
<doc>Closes the current browser.</doc>
<status status="PASS" start="2026-06-26T21:01:28.502075" elapsed="0.020125"/>
</kw>
<doc>Close all browser contexts and the browser itself.</doc>
<status status="PASS" start="2026-06-26T21:01:28.501750" elapsed="0.020548"/>
</kw>
<doc>Log in with the correct password and verify redirect to dashboard.</doc>
<status status="PASS" start="2026-06-26T21:01:26.724737" elapsed="1.797751"/>
</test>
<test id="s1-t3" name="Login With Invalid Password" line="39">
<kw name="Run Keywords" owner="BuiltIn" type="SETUP">
<kw name="Create Anonymous Session" owner="common">
<kw name="Create Session" owner="RequestsLibrary">
<msg time="2026-06-26T21:01:28.530053" level="INFO">Creating Session using : alias=anon, url=http://127.0.0.1:8765, headers={}, cookies={}, auth=None, timeout=None, proxies=None, verify=False, debug=0 </msg>
<arg>anon</arg>
<arg>${BASE_URL}</arg>
<doc>Create Session: create a HTTP session to a server</doc>
<status status="PASS" start="2026-06-26T21:01:28.529897" elapsed="0.000269"/>
</kw>
<doc>Create an unauthenticated HTTP session.</doc>
<status status="PASS" start="2026-06-26T21:01:28.529654" elapsed="0.000576"/>
</kw>
<kw name="Setup Master Password" owner="common">
<kw name="Create Dictionary" owner="BuiltIn">
<msg time="2026-06-26T21:01:28.531073" level="INFO">${payload} = {'master_password': 'TestPass123!', 'anime_directory': '/tmp/aniworld_test_anime', 'name': 'AniworldTest', 'data_dir': 'data', 'scheduler_enabled': 'False', 'logging_level': 'INFO', 'backup_enabled': ...</msg>
<var>${payload}</var>
<arg>master_password=${SETUP_PASSWORD}</arg>
<arg>anime_directory=/tmp/aniworld_test_anime</arg>
<arg>name=AniworldTest</arg>
<arg>data_dir=data</arg>
<arg>scheduler_enabled=False</arg>
<arg>logging_level=INFO</arg>
<arg>backup_enabled=False</arg>
<doc>Creates and returns a dictionary based on the given ``items``.</doc>
<status status="PASS" start="2026-06-26T21:01:28.530645" elapsed="0.000459"/>
</kw>
<kw name="POST On Session" owner="RequestsLibrary">
<msg time="2026-06-26T21:01:28.533080" level="INFO">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"}'
</msg>
<msg time="2026-06-26T21:01:28.533124" level="INFO">POST Response : url=http://127.0.0.1:8765/api/auth/setup
status=400, reason=Bad Request
headers={'date': 'Fri, 26 Jun 2026 19:01:28 GMT', 'server': 'uvicorn', 'content-length': '47', 'content-type': 'application/json'}
body={"detail":"Master password already configured"}
</msg>
<msg time="2026-06-26T21:01:28.533193" level="INFO">${resp} = &lt;Response [400]&gt;</msg>
<var>${resp}</var>
<arg>anon</arg>
<arg>/api/auth/setup</arg>
<arg>json=${payload}</arg>
<arg>expected_status=any</arg>
<doc>Sends a POST request on a previously created HTTP Session.</doc>
<status status="PASS" start="2026-06-26T21:01:28.531210" elapsed="0.002001"/>
</kw>
<if>
<branch type="IF" condition="'${resp.status_code}' == '429'">
<kw name="Sleep" owner="BuiltIn">
<arg>45s</arg>
<doc>Pauses the test executed for the given time.</doc>
<status status="NOT RUN" start="2026-06-26T21:01:28.533710" elapsed="0.000053"/>
</kw>
<kw name="POST On Session" owner="RequestsLibrary">
<var>${resp}</var>
<arg>anon</arg>
<arg>/api/auth/setup</arg>
<arg>json=${payload}</arg>
<arg>expected_status=any</arg>
<doc>Sends a POST request on a previously created HTTP Session.</doc>
<status status="NOT RUN" start="2026-06-26T21:01:28.533844" elapsed="0.000042"/>
</kw>
<status status="NOT RUN" start="2026-06-26T21:01:28.533288" elapsed="0.000632"/>
</branch>
<status status="PASS" start="2026-06-26T21:01:28.533270" elapsed="0.000681"/>
</if>
<if>
<branch type="IF" condition="'${resp.status_code}' == '429'">
<kw name="Sleep" owner="BuiltIn">
<arg>45s</arg>
<doc>Pauses the test executed for the given time.</doc>
<status status="NOT RUN" start="2026-06-26T21:01:28.534342" elapsed="0.000042"/>
</kw>
<kw name="POST On Session" owner="RequestsLibrary">
<var>${resp}</var>
<arg>anon</arg>
<arg>/api/auth/setup</arg>
<arg>json=${payload}</arg>
<arg>expected_status=any</arg>
<doc>Sends a POST request on a previously created HTTP Session.</doc>
<status status="NOT RUN" start="2026-06-26T21:01:28.534456" elapsed="0.000038"/>
</kw>
<status status="NOT RUN" start="2026-06-26T21:01:28.533994" elapsed="0.000533"/>
</branch>
<status status="PASS" start="2026-06-26T21:01:28.533981" elapsed="0.000572"/>
</if>
<if>
<branch type="IF" condition="'${resp.status_code}' == '400'">
<kw name="Convert String To Json" owner="JSONLibrary">
<msg time="2026-06-26T21:01:28.535246" level="INFO">${json} = {'detail': 'Master password already configured'}</msg>
<var>${json}</var>
<arg>${resp.text}</arg>
<doc>Convert String to JSON object</doc>
<status status="PASS" start="2026-06-26T21:01:28.534919" elapsed="0.000348"/>
</kw>
<kw name="Get Value From Json" owner="JSONLibrary">
<msg time="2026-06-26T21:01:28.545940" level="INFO">${detail} = ['Master password already configured']</msg>
<var>${detail}</var>
<arg>${json}</arg>
<arg>$.detail</arg>
<doc>Get Value From JSON using JSONPath</doc>
<status status="PASS" start="2026-06-26T21:01:28.535349" elapsed="0.010625"/>
</kw>
<if>
<branch type="IF" condition="'${detail}[0]' == 'Master password already configured'">
<return>
<status status="PASS" start="2026-06-26T21:01:28.546267" elapsed="0.000058"/>
</return>
<status status="PASS" start="2026-06-26T21:01:28.546063" elapsed="0.000296"/>
</branch>
<status status="PASS" start="2026-06-26T21:01:28.546044" elapsed="0.000341"/>
</if>
<kw name="Fail" owner="BuiltIn">
<arg>Setup failed with 400: ${detail}</arg>
<doc>Fails the test with the given message and optionally alters its tags.</doc>
<status status="NOT RUN" start="2026-06-26T21:01:28.546470" elapsed="0.000047"/>
</kw>
<status status="PASS" start="2026-06-26T21:01:28.534589" elapsed="0.011959"/>
</branch>
<status status="PASS" start="2026-06-26T21:01:28.534579" elapsed="0.011994"/>
</if>
<if>
<branch type="IF" condition="'${resp.status_code}' == '201'">
<kw name="Should Be Equal As Integers" owner="BuiltIn">
<arg>${resp.status_code}</arg>
<arg>201</arg>
<doc>Fails if objects are unequal after converting them to integers.</doc>
<status status="NOT RUN" start="2026-06-26T21:01:28.546704" elapsed="0.000055"/>
</kw>
<return>
<status status="NOT RUN" start="2026-06-26T21:01:28.546799" elapsed="0.000039"/>
</return>
<status status="NOT RUN" start="2026-06-26T21:01:28.546609" elapsed="0.000254"/>
</branch>
<status status="NOT RUN" start="2026-06-26T21:01:28.546599" elapsed="0.000287"/>
</if>
<kw name="Fail" owner="BuiltIn">
<arg>Unexpected status ${resp.status_code} from /api/auth/setup</arg>
<doc>Fails the test with the given message and optionally alters its tags.</doc>
<status status="NOT RUN" start="2026-06-26T21:01:28.546944" elapsed="0.000040"/>
</kw>
<doc>Configure the master password via the setup endpoint.</doc>
<status status="PASS" start="2026-06-26T21:01:28.530445" elapsed="0.016595"/>
</kw>
<arg>Create Anonymous Session</arg>
<arg>AND</arg>
<arg>Setup Master Password</arg>
<doc>Executes all the given keywords in a sequence.</doc>
<status status="PASS" start="2026-06-26T21:01:28.529219" elapsed="0.017862"/>
</kw>
<kw name="Open Browser To Page" owner="common">
<kw name="New Page" owner="Browser">
<msg time="2026-06-26T21:01:29.052219" level="INFO">Successfully initialized new page object and opened url: http://127.0.0.1:8765/login</msg>
<msg time="2026-06-26T21:01:29.052286" level="INFO">No browser and context was open. New browser and context was automatically opened when page is created.</msg>
<arg>${BASE_URL}${path}</arg>
<tag>BrowserControl</tag>
<tag>Setter</tag>
<doc>Open a new Page.</doc>
<status status="PASS" start="2026-06-26T21:01:28.547438" elapsed="0.504985"/>
</kw>
<arg>/login</arg>
<doc>Open a new page at the given path relative to BASE_URL.</doc>
<status status="PASS" start="2026-06-26T21:01:28.547198" elapsed="0.505343"/>
</kw>
<kw name="Fill Text" owner="Browser">
<msg time="2026-06-26T21:01:29.053435" level="INFO">Fills the text 'WrongPass123!' in the given field.</msg>
<arg>id=password-input</arg>
<arg>WrongPass123!</arg>
<tag>PageContent</tag>
<tag>Setter</tag>
<doc>Clears and fills the given ``txt`` into the text field found by ``selector``.</doc>
<status status="PASS" start="2026-06-26T21:01:29.052704" elapsed="0.023399"/>
</kw>
<kw name="Click" owner="Browser">
<msg time="2026-06-26T21:01:29.076713" level="INFO">Clicks the element 'id=login-submit-btn'.</msg>
<arg>id=login-submit-btn</arg>
<tag>PageContent</tag>
<tag>Setter</tag>
<doc>Simulates mouse click on the element found by ``selector``.</doc>
<status status="PASS" start="2026-06-26T21:01:29.076280" elapsed="0.035844"/>
</kw>
<kw name="Element Should Be Visible" owner="ui_keywords">
<kw name="Wait For Elements State" owner="Browser">
<msg time="2026-06-26T21:01:29.139954" level="INFO">Waited for Element with selector id=login-error at state visible</msg>
<arg>${selector}</arg>
<arg>visible</arg>
<arg>timeout=5s</arg>
<tag>PageContent</tag>
<tag>Wait</tag>
<doc>Waits for the element found by ``selector`` to satisfy state option.</doc>
<status status="PASS" start="2026-06-26T21:01:29.112616" elapsed="0.027514"/>
</kw>
<arg>id=login-error</arg>
<doc>Assert that the element matching the selector is visible.</doc>
<status status="PASS" start="2026-06-26T21:01:29.112320" elapsed="0.027913"/>
</kw>
<kw name="Element Text Should Contain" owner="ui_keywords">
<kw name="Get Text" owner="Browser">
<msg time="2026-06-26T21:01:29.160376" level="INFO">Text: ['invalid credentials']</msg>
<msg time="2026-06-26T21:01:29.160498" level="INFO">${element_text} = invalid credentials</msg>
<var>${element_text}</var>
<arg>${selector}</arg>
<tag>Assertion</tag>
<tag>Getter</tag>
<tag>PageContent</tag>
<doc>Returns text attribute of the element found by ``selector``.</doc>
<status status="PASS" start="2026-06-26T21:01:29.140736" elapsed="0.019783"/>
</kw>
<kw name="Should Contain" owner="BuiltIn">
<arg>${element_text}</arg>
<arg>${text}</arg>
<doc>Fails if ``container`` does not contain ``item`` one or more times.</doc>
<status status="PASS" start="2026-06-26T21:01:29.160669" elapsed="0.000376"/>
</kw>
<arg>id=login-error</arg>
<arg>invalid</arg>
<doc>Assert that the element's text contains the given substring.</doc>
<status status="PASS" start="2026-06-26T21:01:29.140394" elapsed="0.020717"/>
</kw>
<kw name="Close Browser" owner="common" type="TEARDOWN">
<kw name="Close Browser" owner="Browser">
<msg time="2026-06-26T21:01:29.177705" level="INFO">Closed all browsers</msg>
<arg>ALL</arg>
<tag>BrowserControl</tag>
<tag>Setter</tag>
<doc>Closes the current browser.</doc>
<status status="PASS" start="2026-06-26T21:01:29.161530" elapsed="0.016324"/>
</kw>
<doc>Close all browser contexts and the browser itself.</doc>
<status status="PASS" start="2026-06-26T21:01:29.161272" elapsed="0.016674"/>
</kw>
<doc>Log in with an incorrect password and verify error message.</doc>
<status status="PASS" start="2026-06-26T21:01:28.526756" elapsed="0.651233"/>
</test>
<test id="s1-t4" name="Login Rate Limit UI" line="50">
<kw name="Run Keywords" owner="BuiltIn" type="SETUP">
<kw name="Create Anonymous Session" owner="common">
<kw name="Create Session" owner="RequestsLibrary">
<msg time="2026-06-26T21:01:29.185318" level="INFO">Creating Session using : alias=anon, url=http://127.0.0.1:8765, headers={}, cookies={}, auth=None, timeout=None, proxies=None, verify=False, debug=0 </msg>
<arg>anon</arg>
<arg>${BASE_URL}</arg>
<doc>Create Session: create a HTTP session to a server</doc>
<status status="PASS" start="2026-06-26T21:01:29.185160" elapsed="0.000273"/>
</kw>
<doc>Create an unauthenticated HTTP session.</doc>
<status status="PASS" start="2026-06-26T21:01:29.184905" elapsed="0.000593"/>
</kw>
<kw name="Setup Master Password" owner="common">
<kw name="Create Dictionary" owner="BuiltIn">
<msg time="2026-06-26T21:01:29.186394" level="INFO">${payload} = {'master_password': 'TestPass123!', 'anime_directory': '/tmp/aniworld_test_anime', 'name': 'AniworldTest', 'data_dir': 'data', 'scheduler_enabled': 'False', 'logging_level': 'INFO', 'backup_enabled': ...</msg>
<var>${payload}</var>
<arg>master_password=${SETUP_PASSWORD}</arg>
<arg>anime_directory=/tmp/aniworld_test_anime</arg>
<arg>name=AniworldTest</arg>
<arg>data_dir=data</arg>
<arg>scheduler_enabled=False</arg>
<arg>logging_level=INFO</arg>
<arg>backup_enabled=False</arg>
<doc>Creates and returns a dictionary based on the given ``items``.</doc>
<status status="PASS" start="2026-06-26T21:01:29.186041" elapsed="0.000378"/>
</kw>
<kw name="POST On Session" owner="RequestsLibrary">
<msg time="2026-06-26T21:01:29.188374" level="INFO">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"}'
</msg>
<msg time="2026-06-26T21:01:29.188437" level="INFO">POST Response : url=http://127.0.0.1:8765/api/auth/setup
status=400, reason=Bad Request
headers={'date': 'Fri, 26 Jun 2026 19:01:28 GMT', 'server': 'uvicorn', 'content-length': '47', 'content-type': 'application/json'}
body={"detail":"Master password already configured"}
</msg>
<msg time="2026-06-26T21:01:29.188521" level="INFO">${resp} = &lt;Response [400]&gt;</msg>
<var>${resp}</var>
<arg>anon</arg>
<arg>/api/auth/setup</arg>
<arg>json=${payload}</arg>
<arg>expected_status=any</arg>
<doc>Sends a POST request on a previously created HTTP Session.</doc>
<status status="PASS" start="2026-06-26T21:01:29.186519" elapsed="0.002021"/>
</kw>
<if>
<branch type="IF" condition="'${resp.status_code}' == '429'">
<kw name="Sleep" owner="BuiltIn">
<arg>45s</arg>
<doc>Pauses the test executed for the given time.</doc>
<status status="NOT RUN" start="2026-06-26T21:01:29.189167" elapsed="0.000059"/>
</kw>
<kw name="POST On Session" owner="RequestsLibrary">
<var>${resp}</var>
<arg>anon</arg>
<arg>/api/auth/setup</arg>
<arg>json=${payload}</arg>
<arg>expected_status=any</arg>
<doc>Sends a POST request on a previously created HTTP Session.</doc>
<status status="NOT RUN" start="2026-06-26T21:01:29.189315" elapsed="0.000076"/>
</kw>
<status status="NOT RUN" start="2026-06-26T21:01:29.188639" elapsed="0.000786"/>
</branch>
<status status="PASS" start="2026-06-26T21:01:29.188613" elapsed="0.000844"/>
</if>
<if>
<branch type="IF" condition="'${resp.status_code}' == '429'">
<kw name="Sleep" owner="BuiltIn">
<arg>45s</arg>
<doc>Pauses the test executed for the given time.</doc>
<status status="NOT RUN" start="2026-06-26T21:01:29.189942" elapsed="0.000098"/>
</kw>
<kw name="POST On Session" owner="RequestsLibrary">
<var>${resp}</var>
<arg>anon</arg>
<arg>/api/auth/setup</arg>
<arg>json=${payload}</arg>
<arg>expected_status=any</arg>
<doc>Sends a POST request on a previously created HTTP Session.</doc>
<status status="NOT RUN" start="2026-06-26T21:01:29.190196" elapsed="0.000070"/>
</kw>
<status status="NOT RUN" start="2026-06-26T21:01:29.189500" elapsed="0.000806"/>
</branch>
<status status="PASS" start="2026-06-26T21:01:29.189488" elapsed="0.000849"/>
</if>
<if>
<branch type="IF" condition="'${resp.status_code}' == '400'">
<kw name="Convert String To Json" owner="JSONLibrary">
<msg time="2026-06-26T21:01:29.191243" level="INFO">${json} = {'detail': 'Master password already configured'}</msg>
<var>${json}</var>
<arg>${resp.text}</arg>
<doc>Convert String to JSON object</doc>
<status status="PASS" start="2026-06-26T21:01:29.190865" elapsed="0.000402"/>
</kw>
<kw name="Get Value From Json" owner="JSONLibrary">
<msg time="2026-06-26T21:01:29.207546" level="INFO">${detail} = ['Master password already configured']</msg>
<var>${detail}</var>
<arg>${json}</arg>
<arg>$.detail</arg>
<doc>Get Value From JSON using JSONPath</doc>
<status status="PASS" start="2026-06-26T21:01:29.191356" elapsed="0.016245"/>
</kw>
<if>
<branch type="IF" condition="'${detail}[0]' == 'Master password already configured'">
<return>
<status status="PASS" start="2026-06-26T21:01:29.208194" elapsed="0.000089"/>
</return>
<status status="PASS" start="2026-06-26T21:01:29.207931" elapsed="0.000409"/>
</branch>
<status status="PASS" start="2026-06-26T21:01:29.207898" elapsed="0.000486"/>
</if>
<kw name="Fail" owner="BuiltIn">
<arg>Setup failed with 400: ${detail}</arg>
<doc>Fails the test with the given message and optionally alters its tags.</doc>
<status status="NOT RUN" start="2026-06-26T21:01:29.208525" elapsed="0.000094"/>
</kw>
<status status="PASS" start="2026-06-26T21:01:29.190387" elapsed="0.018286"/>
</branch>
<status status="PASS" start="2026-06-26T21:01:29.190371" elapsed="0.018353"/>
</if>
<if>
<branch type="IF" condition="'${resp.status_code}' == '201'">
<kw name="Should Be Equal As Integers" owner="BuiltIn">
<arg>${resp.status_code}</arg>
<arg>201</arg>
<doc>Fails if objects are unequal after converting them to integers.</doc>
<status status="NOT RUN" start="2026-06-26T21:01:29.208956" elapsed="0.000066"/>
</kw>
<return>
<status status="NOT RUN" start="2026-06-26T21:01:29.209079" elapsed="0.000058"/>
</return>
<status status="NOT RUN" start="2026-06-26T21:01:29.208787" elapsed="0.000385"/>
</branch>
<status status="NOT RUN" start="2026-06-26T21:01:29.208771" elapsed="0.000435"/>
</if>
<kw name="Fail" owner="BuiltIn">
<arg>Unexpected status ${resp.status_code} from /api/auth/setup</arg>
<doc>Fails the test with the given message and optionally alters its tags.</doc>
<status status="NOT RUN" start="2026-06-26T21:01:29.209286" elapsed="0.000065"/>
</kw>
<doc>Configure the master password via the setup endpoint.</doc>
<status status="PASS" start="2026-06-26T21:01:29.185771" elapsed="0.023644"/>
</kw>
<arg>Create Anonymous Session</arg>
<arg>AND</arg>
<arg>Setup Master Password</arg>
<doc>Executes all the given keywords in a sequence.</doc>
<status status="PASS" start="2026-06-26T21:01:29.184436" elapsed="0.025023"/>
</kw>
<kw name="Open Browser To Page" owner="common">
<kw name="New Page" owner="Browser">
<msg time="2026-06-26T21:01:29.639749" level="INFO">Successfully initialized new page object and opened url: http://127.0.0.1:8765/login</msg>
<msg time="2026-06-26T21:01:29.639830" level="INFO">No browser and context was open. New browser and context was automatically opened when page is created.</msg>
<arg>${BASE_URL}${path}</arg>
<tag>BrowserControl</tag>
<tag>Setter</tag>
<doc>Open a new Page.</doc>
<status status="PASS" start="2026-06-26T21:01:29.209866" elapsed="0.430124"/>
</kw>
<arg>/login</arg>
<doc>Open a new page at the given path relative to BASE_URL.</doc>
<status status="PASS" start="2026-06-26T21:01:29.209585" elapsed="0.430534"/>
</kw>
<for flavor="IN RANGE">
<iter>
<kw name="Fill Text" owner="Browser">
<msg time="2026-06-26T21:01:29.642695" level="INFO">Fills the text 'WrongPass123!' in the given field.</msg>
<arg>id=password-input</arg>
<arg>WrongPass123!</arg>
<tag>PageContent</tag>
<tag>Setter</tag>
<doc>Clears and fills the given ``txt`` into the text field found by ``selector``.</doc>
<status status="PASS" start="2026-06-26T21:01:29.642190" elapsed="0.029472"/>
</kw>
<kw name="Click" owner="Browser">
<msg time="2026-06-26T21:01:29.672599" level="INFO">Clicks the element 'id=login-submit-btn'.</msg>
<arg>id=login-submit-btn</arg>
<tag>PageContent</tag>
<tag>Setter</tag>
<doc>Simulates mouse click on the element found by ``selector``.</doc>
<status status="PASS" start="2026-06-26T21:01:29.672008" elapsed="0.044643"/>
</kw>
<kw name="Wait For Elements State" owner="Browser">
<msg time="2026-06-26T21:01:29.748878" level="INFO">Waited for Element with selector id=login-error at state visible</msg>
<arg>id=login-error</arg>
<arg>visible</arg>
<arg>timeout=3s</arg>
<tag>PageContent</tag>
<tag>Wait</tag>
<doc>Waits for the element found by ``selector`` to satisfy state option.</doc>
<status status="PASS" start="2026-06-26T21:01:29.716902" elapsed="0.032167"/>
</kw>
<var name="${i}">0</var>
<status status="PASS" start="2026-06-26T21:01:29.641666" elapsed="0.107504"/>
</iter>
<iter>
<kw name="Fill Text" owner="Browser">
<msg time="2026-06-26T21:01:29.750027" level="INFO">Fills the text 'WrongPass123!' in the given field.</msg>
<arg>id=password-input</arg>
<arg>WrongPass123!</arg>
<tag>PageContent</tag>
<tag>Setter</tag>
<doc>Clears and fills the given ``txt`` into the text field found by ``selector``.</doc>
<status status="PASS" start="2026-06-26T21:01:29.749623" elapsed="0.011487"/>
</kw>
<kw name="Click" owner="Browser">
<msg time="2026-06-26T21:01:29.761943" level="INFO">Clicks the element 'id=login-submit-btn'.</msg>
<arg>id=login-submit-btn</arg>
<tag>PageContent</tag>
<tag>Setter</tag>
<doc>Simulates mouse click on the element found by ``selector``.</doc>
<status status="PASS" start="2026-06-26T21:01:29.761362" elapsed="0.249246"/>
</kw>
<kw name="Wait For Elements State" owner="Browser">
<msg time="2026-06-26T21:01:30.041208" level="INFO">Waited for Element with selector id=login-error at state visible</msg>
<arg>id=login-error</arg>
<arg>visible</arg>
<arg>timeout=3s</arg>
<tag>PageContent</tag>
<tag>Wait</tag>
<doc>Waits for the element found by ``selector`` to satisfy state option.</doc>
<status status="PASS" start="2026-06-26T21:01:30.010857" elapsed="0.030497"/>
</kw>
<var name="${i}">1</var>
<status status="PASS" start="2026-06-26T21:01:29.749362" elapsed="0.292059"/>
</iter>
<iter>
<kw name="Fill Text" owner="Browser">
<msg time="2026-06-26T21:01:30.042108" level="INFO">Fills the text 'WrongPass123!' in the given field.</msg>
<arg>id=password-input</arg>
<arg>WrongPass123!</arg>
<tag>PageContent</tag>
<tag>Setter</tag>
<doc>Clears and fills the given ``txt`` into the text field found by ``selector``.</doc>
<status status="PASS" start="2026-06-26T21:01:30.041746" elapsed="0.006007"/>
</kw>
<kw name="Click" owner="Browser">
<msg time="2026-06-26T21:01:30.048581" level="INFO">Clicks the element 'id=login-submit-btn'.</msg>
<arg>id=login-submit-btn</arg>
<tag>PageContent</tag>
<tag>Setter</tag>
<doc>Simulates mouse click on the element found by ``selector``.</doc>
<status status="PASS" start="2026-06-26T21:01:30.048002" elapsed="0.061963"/>
</kw>
<kw name="Wait For Elements State" owner="Browser">
<msg time="2026-06-26T21:01:30.135409" level="INFO">Waited for Element with selector id=login-error at state visible</msg>
<arg>id=login-error</arg>
<arg>visible</arg>
<arg>timeout=3s</arg>
<tag>PageContent</tag>
<tag>Wait</tag>
<doc>Waits for the element found by ``selector`` to satisfy state option.</doc>
<status status="PASS" start="2026-06-26T21:01:30.110146" elapsed="0.025467"/>
</kw>
<var name="${i}">2</var>
<status status="PASS" start="2026-06-26T21:01:30.041547" elapsed="0.094174"/>
</iter>
<iter>
<kw name="Fill Text" owner="Browser">
<msg time="2026-06-26T21:01:30.136650" level="INFO">Fills the text 'WrongPass123!' in the given field.</msg>
<arg>id=password-input</arg>
<arg>WrongPass123!</arg>
<tag>PageContent</tag>
<tag>Setter</tag>
<doc>Clears and fills the given ``txt`` into the text field found by ``selector``.</doc>
<status status="PASS" start="2026-06-26T21:01:30.136150" elapsed="0.006710"/>
</kw>
<kw name="Click" owner="Browser">
<msg time="2026-06-26T21:01:30.143444" level="INFO">Clicks the element 'id=login-submit-btn'.</msg>
<arg>id=login-submit-btn</arg>
<tag>PageContent</tag>
<tag>Setter</tag>
<doc>Simulates mouse click on the element found by ``selector``.</doc>
<status status="PASS" start="2026-06-26T21:01:30.143035" elapsed="0.066844"/>
</kw>
<kw name="Wait For Elements State" owner="Browser">
<msg time="2026-06-26T21:01:30.235892" level="INFO">Waited for Element with selector id=login-error at state visible</msg>
<arg>id=login-error</arg>
<arg>visible</arg>
<arg>timeout=3s</arg>
<tag>PageContent</tag>
<tag>Wait</tag>
<doc>Waits for the element found by ``selector`` to satisfy state option.</doc>
<status status="PASS" start="2026-06-26T21:01:30.210063" elapsed="0.026014"/>
</kw>
<var name="${i}">3</var>
<status status="PASS" start="2026-06-26T21:01:30.135895" elapsed="0.100266"/>
</iter>
<iter>
<kw name="Fill Text" owner="Browser">
<msg time="2026-06-26T21:01:30.237188" level="INFO">Fills the text 'WrongPass123!' in the given field.</msg>
<arg>id=password-input</arg>
<arg>WrongPass123!</arg>
<tag>PageContent</tag>
<tag>Setter</tag>
<doc>Clears and fills the given ``txt`` into the text field found by ``selector``.</doc>
<status status="PASS" start="2026-06-26T21:01:30.236540" elapsed="0.006670"/>
</kw>
<kw name="Click" owner="Browser">
<msg time="2026-06-26T21:01:30.243806" level="INFO">Clicks the element 'id=login-submit-btn'.</msg>
<arg>id=login-submit-btn</arg>
<tag>PageContent</tag>
<tag>Setter</tag>
<doc>Simulates mouse click on the element found by ``selector``.</doc>
<status status="PASS" start="2026-06-26T21:01:30.243387" elapsed="0.066894"/>
</kw>
<kw name="Wait For Elements State" owner="Browser">
<msg time="2026-06-26T21:01:30.336576" level="INFO">Waited for Element with selector id=login-error at state visible</msg>
<arg>id=login-error</arg>
<arg>visible</arg>
<arg>timeout=3s</arg>
<tag>PageContent</tag>
<tag>Wait</tag>
<doc>Waits for the element found by ``selector`` to satisfy state option.</doc>
<status status="PASS" start="2026-06-26T21:01:30.310530" elapsed="0.026202"/>
</kw>
<var name="${i}">4</var>
<status status="PASS" start="2026-06-26T21:01:30.236309" elapsed="0.100494"/>
</iter>
<iter>
<kw name="Fill Text" owner="Browser">
<msg time="2026-06-26T21:01:30.337572" level="INFO">Fills the text 'WrongPass123!' in the given field.</msg>
<arg>id=password-input</arg>
<arg>WrongPass123!</arg>
<tag>PageContent</tag>
<tag>Setter</tag>
<doc>Clears and fills the given ``txt`` into the text field found by ``selector``.</doc>
<status status="PASS" start="2026-06-26T21:01:30.337122" elapsed="0.006515"/>
</kw>
<kw name="Click" owner="Browser">
<msg time="2026-06-26T21:01:30.344236" level="INFO">Clicks the element 'id=login-submit-btn'.</msg>
<arg>id=login-submit-btn</arg>
<tag>PageContent</tag>
<tag>Setter</tag>
<doc>Simulates mouse click on the element found by ``selector``.</doc>
<status status="PASS" start="2026-06-26T21:01:30.343826" elapsed="0.066726"/>
</kw>
<kw name="Wait For Elements State" owner="Browser">
<msg time="2026-06-26T21:01:30.436884" level="INFO">Waited for Element with selector id=login-error at state visible</msg>
<arg>id=login-error</arg>
<arg>visible</arg>
<arg>timeout=3s</arg>
<tag>PageContent</tag>
<tag>Wait</tag>
<doc>Waits for the element found by ``selector`` to satisfy state option.</doc>
<status status="PASS" start="2026-06-26T21:01:30.410748" elapsed="0.026282"/>
</kw>
<var name="${i}">5</var>
<status status="PASS" start="2026-06-26T21:01:30.336927" elapsed="0.100174"/>
</iter>
<var>${i}</var>
<value>6</value>
<status status="PASS" start="2026-06-26T21:01:29.640222" elapsed="0.796923"/>
</for>
<kw name="Element Text Should Contain" owner="ui_keywords">
<kw name="Get Text" owner="Browser">
<msg time="2026-06-26T21:01:30.461240" level="INFO">Text: ['Too many authentication attempts, try again later. IP lockout']</msg>
<msg time="2026-06-26T21:01:30.461414" level="INFO">${element_text} = Too many authentication attempts, try again later. IP lockout</msg>
<var>${element_text}</var>
<arg>${selector}</arg>
<tag>Assertion</tag>
<tag>Getter</tag>
<tag>PageContent</tag>
<doc>Returns text attribute of the element found by ``selector``.</doc>
<status status="PASS" start="2026-06-26T21:01:30.437832" elapsed="0.023615"/>
</kw>
<kw name="Should Contain" owner="BuiltIn">
<arg>${element_text}</arg>
<arg>${text}</arg>
<doc>Fails if ``container`` does not contain ``item`` one or more times.</doc>
<status status="PASS" start="2026-06-26T21:01:30.461662" elapsed="0.000509"/>
</kw>
<arg>id=login-error</arg>
<arg>lockout</arg>
<doc>Assert that the element's text contains the given substring.</doc>
<status status="PASS" start="2026-06-26T21:01:30.437327" elapsed="0.024935"/>
</kw>
<kw name="Close Browser" owner="common" type="TEARDOWN">
<kw name="Close Browser" owner="Browser">
<msg time="2026-06-26T21:01:30.486960" level="INFO">Closed all browsers</msg>
<arg>ALL</arg>
<tag>BrowserControl</tag>
<tag>Setter</tag>
<doc>Closes the current browser.</doc>
<status status="PASS" start="2026-06-26T21:01:30.462828" elapsed="0.024323"/>
</kw>
<doc>Close all browser contexts and the browser itself.</doc>
<status status="PASS" start="2026-06-26T21:01:30.462494" elapsed="0.024783"/>
</kw>
<doc>Submit multiple failed logins and verify lockout message appears.</doc>
<status status="PASS" start="2026-06-26T21:01:29.181789" elapsed="1.305547"/>
</test>
<test id="s1-t5" name="Password Visibility Toggle" line="63">
<kw name="Run Keywords" owner="BuiltIn" type="SETUP">
<kw name="Create Anonymous Session" owner="common">
<kw name="Create Session" owner="RequestsLibrary">
<msg time="2026-06-26T21:01:30.499108" level="INFO">Creating Session using : alias=anon, url=http://127.0.0.1:8765, headers={}, cookies={}, auth=None, timeout=None, proxies=None, verify=False, debug=0 </msg>
<arg>anon</arg>
<arg>${BASE_URL}</arg>
<doc>Create Session: create a HTTP session to a server</doc>
<status status="PASS" start="2026-06-26T21:01:30.498888" elapsed="0.000381"/>
</kw>
<doc>Create an unauthenticated HTTP session.</doc>
<status status="PASS" start="2026-06-26T21:01:30.498539" elapsed="0.000822"/>
</kw>
<kw name="Setup Master Password" owner="common">
<kw name="Create Dictionary" owner="BuiltIn">
<msg time="2026-06-26T21:01:30.500461" level="INFO">${payload} = {'master_password': 'TestPass123!', 'anime_directory': '/tmp/aniworld_test_anime', 'name': 'AniworldTest', 'data_dir': 'data', 'scheduler_enabled': 'False', 'logging_level': 'INFO', 'backup_enabled': ...</msg>
<var>${payload}</var>
<arg>master_password=${SETUP_PASSWORD}</arg>
<arg>anime_directory=/tmp/aniworld_test_anime</arg>
<arg>name=AniworldTest</arg>
<arg>data_dir=data</arg>
<arg>scheduler_enabled=False</arg>
<arg>logging_level=INFO</arg>
<arg>backup_enabled=False</arg>
<doc>Creates and returns a dictionary based on the given ``items``.</doc>
<status status="PASS" start="2026-06-26T21:01:30.499992" elapsed="0.000504"/>
</kw>
<kw name="POST On Session" owner="RequestsLibrary">
<msg time="2026-06-26T21:01:30.502433" level="INFO">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"}'
</msg>
<msg time="2026-06-26T21:01:30.502505" level="INFO">POST Response : url=http://127.0.0.1:8765/api/auth/setup
status=429, reason=Too Many Requests
headers={'date': 'Fri, 26 Jun 2026 19:01:30 GMT', 'server': 'uvicorn', 'content-length': '74', 'content-type': 'application/json'}
body={"detail":"Too many authentication attempts, try again later. IP lockout"}
</msg>
<msg time="2026-06-26T21:01:30.502631" level="INFO">${resp} = &lt;Response [429]&gt;</msg>
<var>${resp}</var>
<arg>anon</arg>
<arg>/api/auth/setup</arg>
<arg>json=${payload}</arg>
<arg>expected_status=any</arg>
<doc>Sends a POST request on a previously created HTTP Session.</doc>
<status status="PASS" start="2026-06-26T21:01:30.500640" elapsed="0.002019"/>
</kw>
<if>
<branch type="IF" condition="'${resp.status_code}' == '429'">
<kw name="Sleep" owner="BuiltIn">
<msg time="2026-06-26T21:02:15.503807" level="INFO">Slept 45 seconds.</msg>
<arg>45s</arg>
<doc>Pauses the test executed for the given time.</doc>
<status status="PASS" start="2026-06-26T21:01:30.503382" elapsed="45.000514"/>
</kw>
<kw name="POST On Session" owner="RequestsLibrary">
<msg time="2026-06-26T21:02:15.506036" level="INFO">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"}'
</msg>
<msg time="2026-06-26T21:02:15.506308" level="INFO">POST Response : url=http://127.0.0.1:8765/api/auth/setup
status=429, reason=Too Many Requests
headers={'date': 'Fri, 26 Jun 2026 19:02:15 GMT', 'server': 'uvicorn', 'content-length': '74', 'content-type': 'application/json'}
body={"detail":"Too many authentication attempts, try again later. IP lockout"}
</msg>
<msg time="2026-06-26T21:02:15.506399" level="INFO">${resp} = &lt;Response [429]&gt;</msg>
<var>${resp}</var>
<arg>anon</arg>
<arg>/api/auth/setup</arg>
<arg>json=${payload}</arg>
<arg>expected_status=any</arg>
<doc>Sends a POST request on a previously created HTTP Session.</doc>
<status status="PASS" start="2026-06-26T21:02:15.504038" elapsed="0.002380"/>
</kw>
<status status="PASS" start="2026-06-26T21:01:30.502795" elapsed="45.003675"/>
</branch>
<status status="PASS" start="2026-06-26T21:01:30.502769" elapsed="45.003737"/>
</if>
<if>
<branch type="IF" condition="'${resp.status_code}' == '429'">
<kw name="Sleep" owner="BuiltIn">
<msg time="2026-06-26T21:03:00.507364" level="INFO">Slept 45 seconds.</msg>
<arg>45s</arg>
<doc>Pauses the test executed for the given time.</doc>
<status status="PASS" start="2026-06-26T21:02:15.507003" elapsed="45.000463"/>
</kw>
<kw name="POST On Session" owner="RequestsLibrary">
<msg time="2026-06-26T21:03:00.510007" level="INFO">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"}'
</msg>
<msg time="2026-06-26T21:03:00.510057" level="INFO">POST Response : url=http://127.0.0.1:8765/api/auth/setup
status=400, reason=Bad Request
headers={'date': 'Fri, 26 Jun 2026 19:03:00 GMT', 'server': 'uvicorn', 'content-length': '47', 'content-type': 'application/json'}
body={"detail":"Master password already configured"}
</msg>
<msg time="2026-06-26T21:03:00.510146" level="INFO">${resp} = &lt;Response [400]&gt;</msg>
<var>${resp}</var>
<arg>anon</arg>
<arg>/api/auth/setup</arg>
<arg>json=${payload}</arg>
<arg>expected_status=any</arg>
<doc>Sends a POST request on a previously created HTTP Session.</doc>
<status status="PASS" start="2026-06-26T21:03:00.507623" elapsed="0.002543"/>
</kw>
<status status="PASS" start="2026-06-26T21:02:15.506554" elapsed="45.003666"/>
</branch>
<status status="PASS" start="2026-06-26T21:02:15.506539" elapsed="45.003717"/>
</if>
<if>
<branch type="IF" condition="'${resp.status_code}' == '400'">
<kw name="Convert String To Json" owner="JSONLibrary">
<msg time="2026-06-26T21:03:00.511140" level="INFO">${json} = {'detail': 'Master password already configured'}</msg>
<var>${json}</var>
<arg>${resp.text}</arg>
<doc>Convert String to JSON object</doc>
<status status="PASS" start="2026-06-26T21:03:00.510759" elapsed="0.000405"/>
</kw>
<kw name="Get Value From Json" owner="JSONLibrary">
<msg time="2026-06-26T21:03:00.521814" level="INFO">${detail} = ['Master password already configured']</msg>
<var>${detail}</var>
<arg>${json}</arg>
<arg>$.detail</arg>
<doc>Get Value From JSON using JSONPath</doc>
<status status="PASS" start="2026-06-26T21:03:00.511259" elapsed="0.010594"/>
</kw>
<if>
<branch type="IF" condition="'${detail}[0]' == 'Master password already configured'">
<return>
<status status="PASS" start="2026-06-26T21:03:00.522158" elapsed="0.000067"/>
</return>
<status status="PASS" start="2026-06-26T21:03:00.521952" elapsed="0.000309"/>
</branch>
<status status="PASS" start="2026-06-26T21:03:00.521932" elapsed="0.000356"/>
</if>
<kw name="Fail" owner="BuiltIn">
<arg>Setup failed with 400: ${detail}</arg>
<doc>Fails the test with the given message and optionally alters its tags.</doc>
<status status="NOT RUN" start="2026-06-26T21:03:00.522381" elapsed="0.000050"/>
</kw>
<status status="PASS" start="2026-06-26T21:03:00.510306" elapsed="0.012159"/>
</branch>
<status status="PASS" start="2026-06-26T21:03:00.510291" elapsed="0.012200"/>
</if>
<if>
<branch type="IF" condition="'${resp.status_code}' == '201'">
<kw name="Should Be Equal As Integers" owner="BuiltIn">
<arg>${resp.status_code}</arg>
<arg>201</arg>
<doc>Fails if objects are unequal after converting them to integers.</doc>
<status status="NOT RUN" start="2026-06-26T21:03:00.522625" elapsed="0.000042"/>
</kw>
<return>
<status status="NOT RUN" start="2026-06-26T21:03:00.522714" elapsed="0.000041"/>
</return>
<status status="NOT RUN" start="2026-06-26T21:03:00.522529" elapsed="0.000250"/>
</branch>
<status status="NOT RUN" start="2026-06-26T21:03:00.522518" elapsed="0.000283"/>
</if>
<kw name="Fail" owner="BuiltIn">
<arg>Unexpected status ${resp.status_code} from /api/auth/setup</arg>
<doc>Fails the test with the given message and optionally alters its tags.</doc>
<status status="NOT RUN" start="2026-06-26T21:03:00.522854" elapsed="0.000041"/>
</kw>
<doc>Configure the master password via the setup endpoint.</doc>
<status status="PASS" start="2026-06-26T21:01:30.499675" elapsed="90.023275"/>
</kw>
<arg>Create Anonymous Session</arg>
<arg>AND</arg>
<arg>Setup Master Password</arg>
<doc>Executes all the given keywords in a sequence.</doc>
<status status="PASS" start="2026-06-26T21:01:30.497893" elapsed="90.025097"/>
</kw>
<kw name="Open Browser To Page" owner="common">
<kw name="New Page" owner="Browser">
<msg time="2026-06-26T21:03:00.965152" level="INFO">Successfully initialized new page object and opened url: http://127.0.0.1:8765/login</msg>
<msg time="2026-06-26T21:03:00.965217" level="INFO">No browser and context was open. New browser and context was automatically opened when page is created.</msg>
<arg>${BASE_URL}${path}</arg>
<tag>BrowserControl</tag>
<tag>Setter</tag>
<doc>Open a new Page.</doc>
<status status="PASS" start="2026-06-26T21:03:00.523394" elapsed="0.441950"/>
</kw>
<arg>/login</arg>
<doc>Open a new page at the given path relative to BASE_URL.</doc>
<status status="PASS" start="2026-06-26T21:03:00.523108" elapsed="0.442331"/>
</kw>
<kw name="Fill Text" owner="Browser">
<msg time="2026-06-26T21:03:00.966049" level="INFO">Fills the text 'TestPass123!' in the given field.</msg>
<arg>id=password-input</arg>
<arg>${SETUP_PASSWORD}</arg>
<tag>PageContent</tag>
<tag>Setter</tag>
<doc>Clears and fills the given ``txt`` into the text field found by ``selector``.</doc>
<status status="PASS" start="2026-06-26T21:03:00.965566" elapsed="0.030035"/>
</kw>
<kw name="Get Attribute" owner="Browser">
<msg time="2026-06-26T21:03:01.015959" level="INFO">Attribute is: 'password'</msg>
<msg time="2026-06-26T21:03:01.016089" level="INFO">${type_before} = password</msg>
<var>${type_before}</var>
<arg>id=password-input</arg>
<arg>type</arg>
<tag>Assertion</tag>
<tag>Getter</tag>
<tag>PageContent</tag>
<doc>Returns the HTML ``attribute`` of the element found by ``selector``.</doc>
<status status="PASS" start="2026-06-26T21:03:00.995796" elapsed="0.020314"/>
</kw>
<kw name="Should Be Equal As Strings" owner="BuiltIn">
<arg>${type_before}</arg>
<arg>password</arg>
<doc>Fails if objects are unequal after converting them to strings.</doc>
<status status="PASS" start="2026-06-26T21:03:01.016291" elapsed="0.000390"/>
</kw>
<kw name="Click" owner="Browser">
<msg time="2026-06-26T21:03:01.017161" level="INFO">Clicks the element 'id=password-toggle'.</msg>
<arg>id=password-toggle</arg>
<tag>PageContent</tag>
<tag>Setter</tag>
<doc>Simulates mouse click on the element found by ``selector``.</doc>
<status status="PASS" start="2026-06-26T21:03:01.016807" elapsed="0.041433"/>
</kw>
<kw name="Get Attribute" owner="Browser">
<msg time="2026-06-26T21:03:01.064323" level="INFO">Attribute is: 'text'</msg>
<msg time="2026-06-26T21:03:01.064444" level="INFO">${type_after} = text</msg>
<var>${type_after}</var>
<arg>id=password-input</arg>
<arg>type</arg>
<tag>Assertion</tag>
<tag>Getter</tag>
<tag>PageContent</tag>
<doc>Returns the HTML ``attribute`` of the element found by ``selector``.</doc>
<status status="PASS" start="2026-06-26T21:03:01.058421" elapsed="0.006045"/>
</kw>
<kw name="Should Be Equal As Strings" owner="BuiltIn">
<arg>${type_after}</arg>
<arg>text</arg>
<doc>Fails if objects are unequal after converting them to strings.</doc>
<status status="PASS" start="2026-06-26T21:03:01.064779" elapsed="0.000341"/>
</kw>
<kw name="Click" owner="Browser">
<msg time="2026-06-26T21:03:01.065532" level="INFO">Clicks the element 'id=password-toggle'.</msg>
<arg>id=password-toggle</arg>
<tag>PageContent</tag>
<tag>Setter</tag>
<doc>Simulates mouse click on the element found by ``selector``.</doc>
<status status="PASS" start="2026-06-26T21:03:01.065229" elapsed="0.041586"/>
</kw>
<kw name="Get Attribute" owner="Browser">
<msg time="2026-06-26T21:03:01.113044" level="INFO">Attribute is: 'password'</msg>
<msg time="2026-06-26T21:03:01.113166" level="INFO">${type_final} = password</msg>
<var>${type_final}</var>
<arg>id=password-input</arg>
<arg>type</arg>
<tag>Assertion</tag>
<tag>Getter</tag>
<tag>PageContent</tag>
<doc>Returns the HTML ``attribute`` of the element found by ``selector``.</doc>
<status status="PASS" start="2026-06-26T21:03:01.107025" elapsed="0.006162"/>
</kw>
<kw name="Should Be Equal As Strings" owner="BuiltIn">
<arg>${type_final}</arg>
<arg>password</arg>
<doc>Fails if objects are unequal after converting them to strings.</doc>
<status status="PASS" start="2026-06-26T21:03:01.113337" elapsed="0.000378"/>
</kw>
<kw name="Close Browser" owner="common" type="TEARDOWN">
<kw name="Close Browser" owner="Browser">
<msg time="2026-06-26T21:03:01.136141" level="INFO">Closed all browsers</msg>
<arg>ALL</arg>
<tag>BrowserControl</tag>
<tag>Setter</tag>
<doc>Closes the current browser.</doc>
<status status="PASS" start="2026-06-26T21:03:01.114128" elapsed="0.022158"/>
</kw>
<doc>Close all browser contexts and the browser itself.</doc>
<status status="PASS" start="2026-06-26T21:03:01.113895" elapsed="0.022486"/>
</kw>
<doc>Click the eye icon and verify the password field type toggles.</doc>
<status status="PASS" start="2026-06-26T21:01:30.494554" elapsed="90.641867"/>
</test>
<test id="s1-t6" name="Logout" line="79">
<kw name="Run Keywords" owner="BuiltIn" type="SETUP">
<kw name="Create Anonymous Session" owner="common">
<kw name="Create Session" owner="RequestsLibrary">
<msg time="2026-06-26T21:03:01.145131" level="INFO">Creating Session using : alias=anon, url=http://127.0.0.1:8765, headers={}, cookies={}, auth=None, timeout=None, proxies=None, verify=False, debug=0 </msg>
<arg>anon</arg>
<arg>${BASE_URL}</arg>
<doc>Create Session: create a HTTP session to a server</doc>
<status status="PASS" start="2026-06-26T21:03:01.144991" elapsed="0.000251"/>
</kw>
<doc>Create an unauthenticated HTTP session.</doc>
<status status="PASS" start="2026-06-26T21:03:01.144758" elapsed="0.000547"/>
</kw>
<kw name="Setup Master Password" owner="common">
<kw name="Create Dictionary" owner="BuiltIn">
<msg time="2026-06-26T21:03:01.146063" level="INFO">${payload} = {'master_password': 'TestPass123!', 'anime_directory': '/tmp/aniworld_test_anime', 'name': 'AniworldTest', 'data_dir': 'data', 'scheduler_enabled': 'False', 'logging_level': 'INFO', 'backup_enabled': ...</msg>
<var>${payload}</var>
<arg>master_password=${SETUP_PASSWORD}</arg>
<arg>anime_directory=/tmp/aniworld_test_anime</arg>
<arg>name=AniworldTest</arg>
<arg>data_dir=data</arg>
<arg>scheduler_enabled=False</arg>
<arg>logging_level=INFO</arg>
<arg>backup_enabled=False</arg>
<doc>Creates and returns a dictionary based on the given ``items``.</doc>
<status status="PASS" start="2026-06-26T21:03:01.145739" elapsed="0.000346"/>
</kw>
<kw name="POST On Session" owner="RequestsLibrary">
<msg time="2026-06-26T21:03:01.148344" level="INFO">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"}'
</msg>
<msg time="2026-06-26T21:03:01.148393" level="INFO">POST Response : url=http://127.0.0.1:8765/api/auth/setup
status=400, reason=Bad Request
headers={'date': 'Fri, 26 Jun 2026 19:03:00 GMT', 'server': 'uvicorn', 'content-length': '47', 'content-type': 'application/json'}
body={"detail":"Master password already configured"}
</msg>
<msg time="2026-06-26T21:03:01.148466" level="INFO">${resp} = &lt;Response [400]&gt;</msg>
<var>${resp}</var>
<arg>anon</arg>
<arg>/api/auth/setup</arg>
<arg>json=${payload}</arg>
<arg>expected_status=any</arg>
<doc>Sends a POST request on a previously created HTTP Session.</doc>
<status status="PASS" start="2026-06-26T21:03:01.146178" elapsed="0.002307"/>
</kw>
<if>
<branch type="IF" condition="'${resp.status_code}' == '429'">
<kw name="Sleep" owner="BuiltIn">
<arg>45s</arg>
<doc>Pauses the test executed for the given time.</doc>
<status status="NOT RUN" start="2026-06-26T21:03:01.149034" elapsed="0.000058"/>
</kw>
<kw name="POST On Session" owner="RequestsLibrary">
<var>${resp}</var>
<arg>anon</arg>
<arg>/api/auth/setup</arg>
<arg>json=${payload}</arg>
<arg>expected_status=any</arg>
<doc>Sends a POST request on a previously created HTTP Session.</doc>
<status status="NOT RUN" start="2026-06-26T21:03:01.149177" elapsed="0.000045"/>
</kw>
<status status="NOT RUN" start="2026-06-26T21:03:01.148570" elapsed="0.000689"/>
</branch>
<status status="PASS" start="2026-06-26T21:03:01.148551" elapsed="0.000740"/>
</if>
<if>
<branch type="IF" condition="'${resp.status_code}' == '429'">
<kw name="Sleep" owner="BuiltIn">
<arg>45s</arg>
<doc>Pauses the test executed for the given time.</doc>
<status status="NOT RUN" start="2026-06-26T21:03:01.149702" elapsed="0.000047"/>
</kw>
<kw name="POST On Session" owner="RequestsLibrary">
<var>${resp}</var>
<arg>anon</arg>
<arg>/api/auth/setup</arg>
<arg>json=${payload}</arg>
<arg>expected_status=any</arg>
<doc>Sends a POST request on a previously created HTTP Session.</doc>
<status status="NOT RUN" start="2026-06-26T21:03:01.149823" elapsed="0.000040"/>
</kw>
<status status="NOT RUN" start="2026-06-26T21:03:01.149334" elapsed="0.000562"/>
</branch>
<status status="PASS" start="2026-06-26T21:03:01.149322" elapsed="0.000600"/>
</if>
<if>
<branch type="IF" condition="'${resp.status_code}' == '400'">
<kw name="Convert String To Json" owner="JSONLibrary">
<msg time="2026-06-26T21:03:01.150626" level="INFO">${json} = {'detail': 'Master password already configured'}</msg>
<var>${json}</var>
<arg>${resp.text}</arg>
<doc>Convert String to JSON object</doc>
<status status="PASS" start="2026-06-26T21:03:01.150291" elapsed="0.000357"/>
</kw>
<kw name="Get Value From Json" owner="JSONLibrary">
<msg time="2026-06-26T21:03:01.161500" level="INFO">${detail} = ['Master password already configured']</msg>
<var>${detail}</var>
<arg>${json}</arg>
<arg>$.detail</arg>
<doc>Get Value From JSON using JSONPath</doc>
<status status="PASS" start="2026-06-26T21:03:01.150736" elapsed="0.010805"/>
</kw>
<if>
<branch type="IF" condition="'${detail}[0]' == 'Master password already configured'">
<return>
<status status="PASS" start="2026-06-26T21:03:01.161884" elapsed="0.000065"/>
</return>
<status status="PASS" start="2026-06-26T21:03:01.161639" elapsed="0.000349"/>
</branch>
<status status="PASS" start="2026-06-26T21:03:01.161620" elapsed="0.000397"/>
</if>
<kw name="Fail" owner="BuiltIn">
<arg>Setup failed with 400: ${detail}</arg>
<doc>Fails the test with the given message and optionally alters its tags.</doc>
<status status="NOT RUN" start="2026-06-26T21:03:01.162115" elapsed="0.000053"/>
</kw>
<status status="PASS" start="2026-06-26T21:03:01.149959" elapsed="0.012244"/>
</branch>
<status status="PASS" start="2026-06-26T21:03:01.149948" elapsed="0.012283"/>
</if>
<if>
<branch type="IF" condition="'${resp.status_code}' == '201'">
<kw name="Should Be Equal As Integers" owner="BuiltIn">
<arg>${resp.status_code}</arg>
<arg>201</arg>
<doc>Fails if objects are unequal after converting them to integers.</doc>
<status status="NOT RUN" start="2026-06-26T21:03:01.162371" elapsed="0.000167"/>
</kw>
<return>
<status status="NOT RUN" start="2026-06-26T21:03:01.162585" elapsed="0.000042"/>
</return>
<status status="NOT RUN" start="2026-06-26T21:03:01.162272" elapsed="0.000381"/>
</branch>
<status status="NOT RUN" start="2026-06-26T21:03:01.162260" elapsed="0.000417"/>
</if>
<kw name="Fail" owner="BuiltIn">
<arg>Unexpected status ${resp.status_code} from /api/auth/setup</arg>
<doc>Fails the test with the given message and optionally alters its tags.</doc>
<status status="NOT RUN" start="2026-06-26T21:03:01.162747" elapsed="0.000057"/>
</kw>
<doc>Configure the master password via the setup endpoint.</doc>
<status status="PASS" start="2026-06-26T21:03:01.145519" elapsed="0.017346"/>
</kw>
<arg>Create Anonymous Session</arg>
<arg>AND</arg>
<arg>Setup Master Password</arg>
<doc>Executes all the given keywords in a sequence.</doc>
<status status="PASS" start="2026-06-26T21:03:01.144298" elapsed="0.018609"/>
</kw>
<kw name="Open Browser To Page" owner="common">
<kw name="New Page" owner="Browser">
<msg time="2026-06-26T21:03:01.494592" level="INFO">Successfully initialized new page object and opened url: http://127.0.0.1:8765/login</msg>
<msg time="2026-06-26T21:03:01.494658" level="INFO">No browser and context was open. New browser and context was automatically opened when page is created.</msg>
<arg>${BASE_URL}${path}</arg>
<tag>BrowserControl</tag>
<tag>Setter</tag>
<doc>Open a new Page.</doc>
<status status="PASS" start="2026-06-26T21:03:01.163292" elapsed="0.331503"/>
</kw>
<arg>/login</arg>
<doc>Open a new page at the given path relative to BASE_URL.</doc>
<status status="PASS" start="2026-06-26T21:03:01.163034" elapsed="0.331856"/>
</kw>
<kw name="Perform Login" owner="ui_keywords">
<kw name="Fill Text" owner="Browser">
<msg time="2026-06-26T21:03:01.495882" level="INFO">Fills the text 'TestPass123!' in the given field.</msg>
<arg>id=password-input</arg>
<arg>${password}</arg>
<tag>PageContent</tag>
<tag>Setter</tag>
<doc>Clears and fills the given ``txt`` into the text field found by ``selector``.</doc>
<status status="PASS" start="2026-06-26T21:03:01.495447" elapsed="0.024224"/>
</kw>
<kw name="Click" owner="Browser">
<msg time="2026-06-26T21:03:01.520399" level="INFO">Clicks the element 'id=login-submit-btn'.</msg>
<arg>id=login-submit-btn</arg>
<tag>PageContent</tag>
<tag>Setter</tag>
<doc>Simulates mouse click on the element found by ``selector``.</doc>
<status status="PASS" start="2026-06-26T21:03:01.519889" elapsed="0.038702"/>
</kw>
<kw name="Wait For Elements State" owner="Browser">
<msg time="2026-06-26T21:03:06.766514" level="INFO" html="true">&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td colspan="3"&gt;&lt;a href="browser/screenshot/fail-screenshot-1.png" target="_blank"&gt;&lt;img src="browser/screenshot/fail-screenshot-1.png" width="800px"/&gt;&lt;/a&gt;</msg>
<msg time="2026-06-26T21:03:06.766674" level="INFO">See also file:///home/lukas/Volume/repo/Aniworld/robot_output/playwright-log.txt for additional details.</msg>
<msg time="2026-06-26T21:03:06.767070" level="FAIL">TimeoutError: locator.waitFor: Timeout 5000ms exceeded.
Call log:
- waiting for locator('id=search-input') to be visible
</msg>
<arg>id=search-input</arg>
<arg>visible</arg>
<arg>timeout=5s</arg>
<tag>PageContent</tag>
<tag>Wait</tag>
<doc>Waits for the element found by ``selector`` to satisfy state option.</doc>
<status status="FAIL" start="2026-06-26T21:03:01.558787" elapsed="5.211336">TimeoutError: locator.waitFor: Timeout 5000ms exceeded.
Call log:
- waiting for locator('id=search-input') to be visible
</status>
</kw>
<arg>${SETUP_PASSWORD}</arg>
<doc>Fill the login form and submit it.</doc>
<status status="FAIL" start="2026-06-26T21:03:01.495051" elapsed="5.275287">TimeoutError: locator.waitFor: Timeout 5000ms exceeded.
Call log:
- waiting for locator('id=search-input') to be visible
</status>
</kw>
<kw name="Perform Logout" owner="ui_keywords">
<doc>Click the logout button and wait for redirect to login.</doc>
<status status="NOT RUN" start="2026-06-26T21:03:06.770558" elapsed="0.000139"/>
</kw>
<kw name="Page Title Should Contain" owner="ui_keywords">
<arg>Login</arg>
<doc>Assert that the page title contains the given text.</doc>
<status status="NOT RUN" start="2026-06-26T21:03:06.770858" elapsed="0.000072"/>
</kw>
<kw name="Element Should Be Visible" owner="ui_keywords">
<arg>id=password-input</arg>
<doc>Assert that the element matching the selector is visible.</doc>
<status status="NOT RUN" start="2026-06-26T21:03:06.771053" elapsed="0.000063"/>
</kw>
<kw name="Close Browser" owner="common" type="TEARDOWN">
<kw name="Close Browser" owner="Browser">
<msg time="2026-06-26T21:03:06.790591" level="INFO">Closed all browsers</msg>
<arg>ALL</arg>
<tag>BrowserControl</tag>
<tag>Setter</tag>
<doc>Closes the current browser.</doc>
<status status="PASS" start="2026-06-26T21:03:06.771670" elapsed="0.019141"/>
</kw>
<doc>Close all browser contexts and the browser itself.</doc>
<status status="PASS" start="2026-06-26T21:03:06.771357" elapsed="0.019580"/>
</kw>
<doc>Log in then log out and verify redirect to login page.</doc>
<status status="FAIL" start="2026-06-26T21:03:01.141148" elapsed="5.649855">TimeoutError: locator.waitFor: Timeout 5000ms exceeded.
Call log:
- waiting for locator('id=search-input') to be visible
</status>
</test>
<doc>Login UI tests for Aniworld.
Covers login page load, valid/invalid login, rate limit UI, password visibility, and logout.</doc>
<status status="FAIL" start="2026-06-26T21:00:40.600889" elapsed="146.195442"/>
</suite>
<statistics>
<total>
<stat pass="5" fail="1" skip="0">All Tests</stat>
</total>
<tag>
</tag>
<suite>
<stat name="Login" id="s1" pass="5" fail="1" skip="0">Login</stat>
</suite>
</statistics>
<errors>
</errors>
</robot>