feat: expand module workflows, dynamic config, notifications and console API

This commit is contained in:
2026-09-04 09:49:37 +08:00
parent 8df5266abb
commit b124d757b0
309 changed files with 89358 additions and 6232 deletions
+142
View File
@@ -0,0 +1,142 @@
from __future__ import annotations
from pathlib import Path
from gyxx_flow.adapters.browser import BrowserCookieStore
from gyxx_flow.adapters.erp_state import (
has_erp_session_cookie,
persist_erp_runtime_state,
restore_erp_runtime_state,
)
class _FakeContext:
def __init__(self) -> None:
self._cookies: list[dict[str, object]] = []
self._storage_state: dict[str, object] = {"cookies": [], "origins": []}
def set_storage_state(self, state: dict[str, object]) -> None:
self._storage_state = state
def add_cookies(self, cookies: list[dict[str, object]]) -> None:
self._cookies.extend(cookies)
def cookies(self) -> list[dict[str, object]]:
return list(self._cookies)
def storage_state(self) -> dict[str, object]:
return dict(self._storage_state)
def _set_state_environment(monkeypatch, root: Path) -> tuple[Path, Path, Path, Path]:
account_cookie = root / "account" / "cookies.json"
account_storage = root / "account" / "storage_state.json"
binding_cookie = root / "binding" / "cookies.json"
binding_storage = root / "binding" / "storage_state.json"
monkeypatch.setenv("GYXX_ACCOUNT_ID", "erp-jushuitan")
monkeypatch.setenv("GYXX_ACCOUNT_COOKIE_FILE", str(account_cookie))
monkeypatch.setenv("GYXX_ACCOUNT_STORAGE_STATE_FILE", str(account_storage))
monkeypatch.setenv("GYXX_BROWSER_COOKIE_FILE", str(binding_cookie))
monkeypatch.setenv("GYXX_BROWSER_STORAGE_STATE_FILE", str(binding_storage))
return account_cookie, account_storage, binding_cookie, binding_storage
def test_account_vault_is_restored_first_and_verified_state_is_persisted(
tmp_path: Path, monkeypatch
) -> None:
account_cookie, account_storage, binding_cookie, binding_storage = (
_set_state_environment(monkeypatch, tmp_path)
)
account_state = [
{
"name": "ASP.NET_SessionId",
"value": "vault-session",
"domain": ".erp321.com",
"path": "/",
}
]
BrowserCookieStore(account_cookie, account_storage).save_cookies(account_state)
BrowserCookieStore(account_cookie, account_storage).save_storage_state(
{"cookies": account_state, "origins": []}
)
binding_state = [
{
"name": "ASP.NET_SessionId",
"value": "old-binding-session",
"domain": ".erp321.com",
"path": "/",
}
]
BrowserCookieStore(binding_cookie, binding_storage).save_cookies(binding_state)
BrowserCookieStore(binding_cookie, binding_storage).save_storage_state(
{"cookies": binding_state, "origins": []}
)
context = _FakeContext()
assert restore_erp_runtime_state(context) == "account vault"
assert context.cookies()[0]["value"] == "vault-session"
context._cookies = [
{
"name": "ASP.NET_SessionId",
"value": "fresh-session",
"domain": ".erp321.com",
"path": "/",
}
]
context._storage_state = {"cookies": context.cookies(), "origins": []}
assert persist_erp_runtime_state(context) == 1
assert BrowserCookieStore(account_cookie, account_storage).load_cookies()[0][
"value"
] == "fresh-session"
assert BrowserCookieStore(binding_cookie, binding_storage).load_cookies()[0][
"value"
] == "fresh-session"
def test_erp_restore_uses_cookies_without_replaying_indexeddb_origins(
tmp_path: Path, monkeypatch
) -> None:
account_cookie, account_storage, _, _ = _set_state_environment(monkeypatch, tmp_path)
cookies = [
{
"name": "ASP.NET_SessionId",
"value": "vault-session",
"domain": ".erp321.com",
"path": "/",
}
]
store = BrowserCookieStore(account_cookie, account_storage)
store.save_cookies(cookies)
store.save_storage_state(
{
"cookies": cookies,
"origins": [
{
"origin": "https://www.erp321.com",
"localStorage": [{"name": "session", "value": "state"}],
"indexedDB": [{"name": "erp", "version": 1}],
}
],
}
)
context = _FakeContext()
assert restore_erp_runtime_state(context) == "account vault"
assert context._storage_state == {"cookies": cookies}
assert context.cookies()[0]["value"] == "vault-session"
def test_erp_session_cookie_detection_accepts_jushuitan_identity_cookie() -> None:
assert has_erp_session_cookie(
[{"name": "u_id", "value": "22469720", "domain": ".erp321.com"}]
)
assert not has_erp_session_cookie(
[{"name": "u_id", "value": "", "domain": ".erp321.com"}]
)
def test_erp_session_cookie_detection_rejects_expired_identity_cookie() -> None:
assert not has_erp_session_cookie(
[{"name": "u_id", "value": "expired", "expires": 1}]
)