Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions agent-notes/improve-report-feedback.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Goal

Give users a clear translated issue-submission failure and next action.

# State

Isolated branch based on improve/integration-contract (PR #1). Changes only the
failure wording and logger message in the existing asynchronous reporting action.
Tests exercise failure, success metadata and cancellation through the generator.

# Decisions and why

Keep report collection/send machinery and existing dialog lifetime. Say the report
was not submitted and offer retry later rather than guessing a network/auth cause.
Use the existing app_elements translation registration; no fabricated translations
or binary catalog edits. New source messages fall back to English until translated.

# Surprises

The original failure text did not explain an action. This slice changes no protocol,
transport, async scheduling, cancellation policy or issue_reporter implementation.

# Next step

Publish and read CI. Controlled generator/service tests do not establish real wx
scheduling, server delivery or live screen-reader output. No merge or release.
6 changes: 3 additions & 3 deletions app_elements/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,10 @@ def report_issue(*args, **kwargs):
try:
yield Task(application.issue_reporter.send_report, report)
except Exception as e:
logger.exception("Error submitting issue report. Not a good day.")
logger.exception("Error submitting issue report")
popups.warning_message(
title=_("Error"),
message=_("There was an issue submitting your issue report. Badness."),
title=_("Issue report not submitted"),
message=_("Your issue report could not be submitted. Please try again later."),
)
return
popups.message_box(title=_("Issue submitted"), message=_("Thanks for your report!"))
Expand Down
67 changes: 67 additions & 0 deletions tests/test_report_feedback.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import types
import unittest
from unittest.mock import Mock, patch

from support import load_component


class ReportFeedbackTests(unittest.TestCase):
def dialog(self, modules, result=1):
report = types.SimpleNamespace(log_paths=[])
dialog = Mock()
dialog.display_modal.return_value = result
dialog.get_report.return_value = report
gui = types.ModuleType("issue_reporter.gui")
gui.IssueReporterDialog = Mock(return_value=dialog)
package = types.ModuleType("issue_reporter")
package.gui = gui
modules.update({"issue_reporter": package, "issue_reporter.gui": gui})
return dialog, report

def application_values(self):
return dict(main_window=object(), version="1.2", error_log_path="example.log",
issue_reporter=Mock())

def test_send_failure_warns_without_a_success_message(self):
with load_component("app_elements.interface", **self.application_values()) as (component, app, modules):
dialog, report = self.dialog(modules)
with patch.dict("sys.modules", modules):
operation = component.report_issue()
next(operation)
dialog.destroy.assert_called_once()
modules["app_framework.background"].Task.assert_called_once_with(app.issue_reporter.send_report, report)
with self.assertLogs("app_elements.interface", level="ERROR"):
with self.assertRaises(StopIteration):
operation.throw(ConnectionError("offline"))
warning = modules["wx_utils.popups"].warning_message
warning.assert_called_once_with(
title="Issue report not submitted",
message="Your issue report could not be submitted. Please try again later.",
)
modules["wx_utils.popups"].message_box.assert_not_called()

def test_success_keeps_report_metadata_and_confirmation(self):
with load_component("app_elements.interface", **self.application_values()) as (component, app, modules):
dialog, report = self.dialog(modules)
with patch.dict("sys.modules", modules):
operation = component.report_issue()
next(operation)
with self.assertRaises(StopIteration):
operation.send(None)
self.assertEqual(report.application_name, app.name)
self.assertEqual(report.application_version, app.version)
self.assertEqual(report.log_paths, [app.error_log_path])
dialog.destroy.assert_called_once()
modules["wx_utils.popups"].message_box.assert_called_once()
modules["wx_utils.popups"].warning_message.assert_not_called()

def test_cancel_destroys_dialog_without_sending_or_announcing_success(self):
with load_component("app_elements.interface", **self.application_values()) as (component, _, modules):
dialog, _ = self.dialog(modules, result=0)
with patch.dict("sys.modules", modules):
with self.assertRaises(StopIteration):
next(component.report_issue())
dialog.destroy.assert_called_once()
modules["app_framework.background"].Task.assert_not_called()
modules["wx_utils.popups"].message_box.assert_not_called()
modules["wx_utils.popups"].warning_message.assert_not_called()
Loading