157 lines
7.4 KiB
Python
157 lines
7.4 KiB
Python
from datetime import datetime
|
|
|
|
import pytest
|
|
|
|
from playwright_tests.planning import build_plan
|
|
from playwright_tests.setup_page import SetupPage
|
|
|
|
|
|
@pytest.fixture
|
|
def config():
|
|
return {
|
|
"setup": {"run_session": True, "run_token": True},
|
|
"trading_token_idas": {"product_codes": "IDAS,IDASTEST01", "market_code": "NATIONAL"},
|
|
}
|
|
|
|
|
|
def test_combined_plan_dates_and_products(config):
|
|
plan = build_plan(config, now=datetime(2026, 9, 8, 10, 0))
|
|
assert plan["session"] == ("08/09/2026 10:07", "08/09/2026 20:30")
|
|
assert [t["product_code"] for t in plan["tokens"]] == ["IDAS", "IDASTEST01"]
|
|
assert plan["tokens"][0]["delivery_date"] == "09/09/2026"
|
|
assert plan["tokens"][0]["rows"][0] == ("ORDER_NOR", "10:10", "18:30")
|
|
|
|
|
|
def test_login_ignores_expired_mutation_settings(config):
|
|
assert build_plan(config, "login", now=datetime(2026, 9, 8, 23)) == {"session": None, "tokens": []}
|
|
|
|
|
|
def test_token_override_does_not_modify_config(config):
|
|
plan = build_plan(config, "token", "IDASTEST02", datetime(2026, 9, 8, 10))
|
|
assert plan["session"] is None
|
|
assert [t["product_code"] for t in plan["tokens"]] == ["IDASTEST02"]
|
|
assert config["trading_token_idas"]["product_codes"] == "IDAS,IDASTEST01"
|
|
|
|
|
|
@pytest.mark.parametrize("flow, message", [("session", "Session end_time"), ("token", "expiry_time")])
|
|
def test_reject_expired_schedule(config, flow, message):
|
|
with pytest.raises(ValueError, match=message):
|
|
build_plan(config, flow, now=datetime(2026, 9, 8, 23))
|
|
|
|
|
|
def test_reject_inverted_time_session(config):
|
|
config["trading_token_idas"]["time_sessions"] = {"ORDER_NOR": {"start_time": "19:00", "end_time": "18:30"}}
|
|
with pytest.raises(ValueError, match="ORDER_NOR"):
|
|
build_plan(config, "token", now=datetime(2026, 9, 8, 10))
|
|
|
|
|
|
def test_save_waits_for_delayed_confirmation(page, tmp_path):
|
|
page.set_content('''<button onclick="setTimeout(() => {
|
|
document.querySelector('#result').innerHTML = '<div class=alert-success>Saved successfully</div>';
|
|
}, 150)">Save</button><div id=result></div>''')
|
|
app = SetupPage(page, tmp_path)
|
|
app.save("//button", "saved", timeout=2)
|
|
assert len(app.screenshots) == 1
|
|
|
|
|
|
def test_save_rejects_error_dialog(page, tmp_path):
|
|
page.set_content('''<button onclick="alert('Invalid session')">Save</button>''')
|
|
app = SetupPage(page, tmp_path)
|
|
with pytest.raises(AssertionError, match="Invalid session"):
|
|
app.save("//button", "saved", timeout=2)
|
|
assert not app.screenshots
|
|
|
|
|
|
def test_save_accepts_success_dialog(page, tmp_path):
|
|
page.set_content('''<button onclick="alert('Token activated successfully')">Save</button>''')
|
|
app = SetupPage(page, tmp_path)
|
|
app.save("//button", "activated", timeout=2)
|
|
assert app.screenshots
|
|
|
|
|
|
def test_save_does_not_pass_on_click_alone(page, tmp_path):
|
|
page.set_content("<button>Save</button>")
|
|
with pytest.raises(AssertionError, match="no explicit success"):
|
|
SetupPage(page, tmp_path).save("//button", "saved", timeout=0.2)
|
|
|
|
|
|
def test_grid_button_targets_exact_time_session(page, tmp_path):
|
|
page.set_content('''
|
|
<div class=ui-grid-row><span>ORDER_NOR</span><button onclick="window.selected='normal'">Details</button></div>
|
|
<div class=ui-grid-row><span>ORDER_EXCH</span><button onclick="window.selected='exchange'">Details</button></div>
|
|
''')
|
|
SetupPage(page, tmp_path).grid_button("Details", "ORDER_EXCH")
|
|
assert page.evaluate("window.selected") == "exchange"
|
|
|
|
|
|
def test_login_clicks_automatically_after_complete_captcha(page, tmp_path):
|
|
page.route("https://setup.test/", lambda route: route.fulfill(body='''
|
|
<input placeholder="User ID"><input placeholder="Password" type=password>
|
|
<input name=captcha ng-model="login.captcha">
|
|
<button value=Login onclick="window.clickedValue=document.querySelector('[name=captcha]').value;
|
|
document.querySelector('#dashboard').hidden=false;">Sign in</button>
|
|
<span id=dashboard hidden>TRADING MAINTENANCE</span>
|
|
<script>
|
|
setTimeout(() => document.querySelector('[name=captcha]').value='12345', 100);
|
|
setTimeout(() => document.querySelector('[name=captcha]').value='123456', 300);
|
|
</script>
|
|
''', content_type="text/html"))
|
|
app = SetupPage(page, tmp_path)
|
|
app.login({"url": "https://setup.test/", "login": {"username": "sample", "password": "sample"}}, 2000)
|
|
assert page.evaluate("window.clickedValue") == "123456"
|
|
|
|
|
|
def test_token_details_button_can_be_outside_grid(page, tmp_path):
|
|
page.set_content('''<button onclick="window.opened=true">Token Details</button>''')
|
|
SetupPage(page, tmp_path).grid_button("Token Details")
|
|
assert page.evaluate("window.opened") is True
|
|
|
|
|
|
@pytest.mark.parametrize("configured,displayed", [("ORDER_NOR", "ORDER_NORMAL"), ("ORDER_EXCH", "ORDER_EXCHANGE")])
|
|
def test_time_session_aliases_match_live_labels(page, tmp_path, configured, displayed):
|
|
page.set_content(f'''<div class=ui-grid-row><span>{displayed}_OTHER</span>
|
|
<button onclick="window.selected='wrong'">Details</button></div>
|
|
<div class=ui-grid-row><span>{displayed}</span>
|
|
<button onclick="window.selected='correct'">Details</button></div>''')
|
|
SetupPage(page, tmp_path).grid_button("Details", configured)
|
|
assert page.evaluate("window.selected") == "correct"
|
|
|
|
|
|
def test_dropdown_preserves_already_selected_value(page, tmp_path):
|
|
page.set_content('<button id=market onclick="window.clicked=true">NATIONAL</button>')
|
|
SetupPage(page, tmp_path).choose(page.locator("#market"), "NATIONAL")
|
|
assert page.evaluate("window.clicked === undefined")
|
|
|
|
|
|
@pytest.mark.parametrize("message,passes", [("1|Token updated successfully", True), ("0|Invalid session", False)])
|
|
def test_token_save_requires_own_response_despite_old_banner(page, tmp_path, message, passes):
|
|
from tests.locators import Locator
|
|
page.route("https://setup.test/", lambda route: route.fulfill(content_type="text/html", body='''
|
|
<div class=alert-success>Previous token saved successfully</div>
|
|
<button data-ng-click="updateSession()" onclick="fetch('/tokenCtrl/updateTimeSessionMap', {method:'POST'})">Save</button>
|
|
'''))
|
|
page.route("**/tokenCtrl/updateTimeSessionMap", lambda route: route.fulfill(json={"message": message}))
|
|
page.goto("https://setup.test/")
|
|
app = SetupPage(page, tmp_path)
|
|
if passes:
|
|
app.save(Locator.savetimesessionbtn, "saved", timeout=2)
|
|
assert app.screenshots
|
|
else:
|
|
with pytest.raises(AssertionError, match="Invalid session"):
|
|
app.save(Locator.savetimesessionbtn, "saved", timeout=2)
|
|
|
|
|
|
def test_activation_rejects_null_message_even_with_zero_status(page, tmp_path):
|
|
from tests.locators import Locator
|
|
page.route("https://setup.test/", lambda route: route.fulfill(content_type="text/html", body='''
|
|
<div class=ui-grid-row><div role=gridcell>TOKEN123</div><div role=gridcell>ABC</div><div role=gridcell id=active>I</div></div>
|
|
<button data-ng-click="saveTokenDetails('T')" onclick="fetch('/tokenCtrl/updateTokenMstr', {method:'POST'}).then(() => document.querySelector('#active').textContent='T')">Save & Activate</button>
|
|
'''))
|
|
page.route("**/tokenCtrl/updateTokenMstr", lambda route: route.fulfill(json={"message": None, "status": 0}))
|
|
page.goto("https://setup.test/")
|
|
app = SetupPage(page, tmp_path)
|
|
app.token_id = "TOKEN123"
|
|
with pytest.raises(AssertionError, match="Activation not confirmed for token TOKEN123"):
|
|
app.save(Locator.savetokenandactivatebtn, "activated", timeout=2)
|
|
assert not app.screenshots
|