Add ability to send a bug report from within the app
This commit is contained in:
parent
6bc5b66d3f
commit
eedf48dc6a
9 changed files with 345 additions and 25 deletions
195
tests/test_bug_report_dialog.py
Normal file
195
tests/test_bug_report_dialog.py
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
import bouquin.bug_report_dialog as bugmod
|
||||
from bouquin.bug_report_dialog import BugReportDialog
|
||||
|
||||
|
||||
def test_bug_report_truncates_text_to_max_chars(qtbot):
|
||||
dlg = BugReportDialog()
|
||||
qtbot.addWidget(dlg)
|
||||
dlg.show()
|
||||
|
||||
max_chars = getattr(dlg, "MAX_CHARS", 5000)
|
||||
|
||||
# Make a string longer than the allowed maximum
|
||||
long_text = "x" * (max_chars + 50)
|
||||
|
||||
# Setting the text should trigger textChanged -> _enforce_max_length
|
||||
dlg.text_edit.setPlainText(long_text)
|
||||
|
||||
# Let Qt process the signal/slot if needed
|
||||
qtbot.wait(10)
|
||||
|
||||
current = dlg.text_edit.toPlainText()
|
||||
assert len(current) == max_chars
|
||||
assert current == long_text[:max_chars]
|
||||
|
||||
|
||||
def test_bug_report_allows_up_to_max_chars_unchanged(qtbot):
|
||||
dlg = BugReportDialog()
|
||||
qtbot.addWidget(dlg)
|
||||
dlg.show()
|
||||
|
||||
max_chars = getattr(dlg, "MAX_CHARS", 5000)
|
||||
exact_text = "y" * max_chars
|
||||
|
||||
dlg.text_edit.setPlainText(exact_text)
|
||||
qtbot.wait(10)
|
||||
|
||||
current = dlg.text_edit.toPlainText()
|
||||
# Should not be trimmed if it's exactly the limit
|
||||
assert len(current) == max_chars
|
||||
assert current == exact_text
|
||||
|
||||
|
||||
def test_bug_report_send_success_201_shows_info_and_accepts(qtbot, monkeypatch):
|
||||
dlg = BugReportDialog()
|
||||
qtbot.addWidget(dlg)
|
||||
dlg.show()
|
||||
|
||||
# Non-empty message so we don't hit the "empty" warning branch
|
||||
dlg.text_edit.setPlainText("Hello, something broke.")
|
||||
qtbot.wait(10)
|
||||
|
||||
# Make version() deterministic
|
||||
def fake_version(pkg_name):
|
||||
assert pkg_name == "bouquin"
|
||||
return "1.2.3"
|
||||
|
||||
monkeypatch.setattr(
|
||||
bugmod.importlib.metadata, "version", fake_version, raising=True
|
||||
)
|
||||
|
||||
# Capture the POST call and fake a 201 Created response
|
||||
calls = {}
|
||||
|
||||
class DummyResp:
|
||||
status_code = 201
|
||||
|
||||
def fake_post(url, json=None, timeout=None):
|
||||
calls["url"] = url
|
||||
calls["json"] = json
|
||||
calls["timeout"] = timeout
|
||||
return DummyResp()
|
||||
|
||||
monkeypatch.setattr(bugmod.requests, "post", fake_post, raising=True)
|
||||
|
||||
# Capture information / critical message boxes
|
||||
info_called = {}
|
||||
crit_called = {}
|
||||
|
||||
def fake_info(parent, title, text, *a, **k):
|
||||
info_called["title"] = title
|
||||
info_called["text"] = str(text)
|
||||
return 0
|
||||
|
||||
def fake_critical(parent, title, text, *a, **k):
|
||||
crit_called["title"] = title
|
||||
crit_called["text"] = str(text)
|
||||
return 0
|
||||
|
||||
monkeypatch.setattr(
|
||||
bugmod.QMessageBox, "information", staticmethod(fake_info), raising=True
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
bugmod.QMessageBox, "critical", staticmethod(fake_critical), raising=True
|
||||
)
|
||||
|
||||
# Don't actually close the dialog in the test; just record that accept() was called
|
||||
accepted = {}
|
||||
|
||||
def fake_accept():
|
||||
accepted["called"] = True
|
||||
|
||||
dlg.accept = fake_accept
|
||||
|
||||
# Call the send logic directly
|
||||
dlg._send()
|
||||
|
||||
# --- Assertions ---------------------------------------------------------
|
||||
|
||||
# POST was called with the expected URL and JSON payload
|
||||
assert calls["url"] == f"{bugmod.BUG_REPORT_HOST}/{bugmod.ROUTE}"
|
||||
assert calls["json"]["message"] == "Hello, something broke."
|
||||
assert calls["json"]["version"] == "1.2.3"
|
||||
# No attachment fields expected any more
|
||||
|
||||
# Success path: information dialog shown, critical not shown
|
||||
assert "title" in info_called
|
||||
assert "text" in info_called
|
||||
assert crit_called == {}
|
||||
|
||||
# Dialog accepted
|
||||
assert accepted.get("called") is True
|
||||
|
||||
|
||||
def test_bug_report_send_failure_non_201_shows_critical_and_not_accepted(
|
||||
qtbot, monkeypatch
|
||||
):
|
||||
dlg = BugReportDialog()
|
||||
qtbot.addWidget(dlg)
|
||||
dlg.show()
|
||||
|
||||
dlg.text_edit.setPlainText("Broken again.")
|
||||
qtbot.wait(10)
|
||||
|
||||
# Stub version() again
|
||||
monkeypatch.setattr(
|
||||
bugmod.importlib.metadata,
|
||||
"version",
|
||||
lambda name: "9.9.9",
|
||||
raising=True,
|
||||
)
|
||||
|
||||
# Fake a non-201 response (e.g. 500)
|
||||
calls = {}
|
||||
|
||||
class DummyResp:
|
||||
status_code = 500
|
||||
|
||||
def fake_post(url, json=None, timeout=None):
|
||||
calls["url"] = url
|
||||
calls["json"] = json
|
||||
calls["timeout"] = timeout
|
||||
return DummyResp()
|
||||
|
||||
monkeypatch.setattr(bugmod.requests, "post", fake_post, raising=True)
|
||||
|
||||
info_called = {}
|
||||
crit_called = {}
|
||||
|
||||
def fake_info(parent, title, text, *a, **k):
|
||||
info_called["title"] = title
|
||||
info_called["text"] = str(text)
|
||||
return 0
|
||||
|
||||
def fake_critical(parent, title, text, *a, **k):
|
||||
crit_called["title"] = title
|
||||
crit_called["text"] = str(text)
|
||||
return 0
|
||||
|
||||
monkeypatch.setattr(
|
||||
bugmod.QMessageBox, "information", staticmethod(fake_info), raising=True
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
bugmod.QMessageBox, "critical", staticmethod(fake_critical), raising=True
|
||||
)
|
||||
|
||||
accepted = {}
|
||||
|
||||
def fake_accept():
|
||||
accepted["called"] = True
|
||||
|
||||
dlg.accept = fake_accept
|
||||
|
||||
dlg._send()
|
||||
|
||||
# POST still called with JSON payload
|
||||
assert calls["url"] == f"{bugmod.BUG_REPORT_HOST}/{bugmod.ROUTE}"
|
||||
assert calls["json"]["message"] == "Broken again."
|
||||
assert calls["json"]["version"] == "9.9.9"
|
||||
|
||||
# Failure path: critical dialog shown, information not shown
|
||||
assert crit_called # non-empty
|
||||
assert info_called == {}
|
||||
|
||||
# Dialog should NOT be accepted on failure
|
||||
assert accepted.get("called") is not True
|
||||
|
|
@ -80,7 +80,7 @@ def test_load_yesterday_todos_moves_items(qtbot, app, tmp_db_cfg, fresh_db):
|
|||
assert "carry me" not in y_txt or "- [ ]" not in y_txt
|
||||
|
||||
|
||||
def test_open_docs_and_bugs_warning(qtbot, app, fresh_db, tmp_path, monkeypatch):
|
||||
def test_open_docs_warning(qtbot, app, fresh_db, tmp_path, monkeypatch):
|
||||
themes = ThemeManager(app, ThemeConfig(theme=Theme.LIGHT))
|
||||
w = MainWindow(themes=themes)
|
||||
qtbot.addWidget(w)
|
||||
|
|
@ -101,16 +101,12 @@ def test_open_docs_and_bugs_warning(qtbot, app, fresh_db, tmp_path, monkeypatch)
|
|||
t = str(text)
|
||||
if "wiki" in t:
|
||||
called["docs"] = True
|
||||
if "forms/mig5/contact" in t or "contact" in t:
|
||||
called["bugs"] = True
|
||||
return 0
|
||||
|
||||
monkeypatch.setattr(mwmod, "QMessageBox", DummyMB, raising=True) # capture warnings
|
||||
|
||||
# Trigger both actions
|
||||
w._open_docs()
|
||||
w._open_bugs()
|
||||
assert called["docs"] and called["bugs"]
|
||||
assert called["docs"]
|
||||
|
||||
|
||||
def test_export_success_and_error(qtbot, app, fresh_db, tmp_path, monkeypatch):
|
||||
|
|
@ -900,9 +896,7 @@ def test_backup_success_and_error(qtbot, tmp_db_cfg, app, monkeypatch, tmp_path)
|
|||
# ---- Help openers (1152-1169) ----
|
||||
|
||||
|
||||
def test_open_docs_and_bugs_show_warning_on_failure(
|
||||
qtbot, tmp_db_cfg, app, monkeypatch
|
||||
):
|
||||
def test_open_docs_show_warning_on_failure(qtbot, tmp_db_cfg, app, monkeypatch):
|
||||
w = _make_main_window(tmp_db_cfg, app, monkeypatch)
|
||||
qtbot.addWidget(w)
|
||||
|
||||
|
|
@ -914,17 +908,14 @@ def test_open_docs_and_bugs_show_warning_on_failure(
|
|||
def warn(parent, title, text, *a, **k):
|
||||
if "documentation" in title.lower():
|
||||
seen["docs"] = True
|
||||
if "bug" in title.lower():
|
||||
seen["bugs"] = True
|
||||
return 0
|
||||
|
||||
monkeypatch.setattr(
|
||||
mwmod, "QMessageBox", type("MB", (), {"warning": staticmethod(warn)})
|
||||
)
|
||||
w._open_docs()
|
||||
w._open_bugs()
|
||||
|
||||
assert seen["docs"] and seen["bugs"]
|
||||
assert seen["docs"]
|
||||
|
||||
|
||||
def test_open_version(qtbot, tmp_db_cfg, app, monkeypatch):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue