Files
cowork-local/tests/ui/test_jira_knowledge_help_ux.py
T
thanhnvandClaude Opus 5 0cb6035863 fix(jira-knowledge): replace hover tooltip with click-based popup for help button
Native Qt tooltips on macOS are unreliable (delayed or invisible). Replace
with a QFrame popup that appears on click, positioned below the ? button,
and closes when clicking elsewhere (Qt.Popup flag handles ESC and outside-click).

- Store help text in self._help_text instead of setToolTip()
- Add _toggle_help_popup() method: creates/destroys floating QFrame
- Update test to check _help_text attribute instead of toolTip()

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 10:08:15 +09:00

194 lines
7.0 KiB
Python

"""UX tests for Jira Project Knowledge help tooltips and validation.
Verifies that the JiraConnectDialog shows contextual help icons for
Project ID and Jira Key, renders correct help text, supports keyboard
accessibility, and validates common user mistakes (e.g. entering ABC-123
instead of ABC).
"""
from __future__ import annotations
import pytest
class _Config:
"""Minimal config stub for JiraConnectDialog."""
def __init__(self):
self.data = {
"jira": {"base_url": "", "email": "", "api_token": ""},
"jira_knowledge": {"enabled": False, "projects": {}},
}
def save(self):
pass
class _Ctx:
def __init__(self):
self.config = _Config()
def save(self):
self.config.save()
@pytest.fixture
def dialog(qapp):
from cowork_local.ui.connectors_panel import JiraConnectDialog
ctx = _Ctx()
dlg = JiraConnectDialog(ctx)
yield dlg
dlg.deleteLater()
# ---- Help icon presence ---------------------------------------------------
def test_help_icon_exists(dialog):
"""The mapping label row must contain a help button (?)."""
from PySide6.QtWidgets import QToolButton
dlg = dialog
help_icons = dlg.findChildren(QToolButton)
assert len(help_icons) >= 1, "Help button (?) not found in JiraConnectDialog"
def test_help_icon_has_tooltip(dialog):
"""Help icon must store help text with both Project ID and Jira Key explanations."""
from PySide6.QtWidgets import QToolButton
dlg = dialog
help_icons = dlg.findChildren(QToolButton)
assert help_icons, "No help button found"
# Help text is stored in _help_text for click-based popup
help_text = getattr(dlg, '_help_text', '') or help_icons[0].toolTip()
assert help_text, "Help button has no help content"
assert "Project ID" in help_text, "Help content missing Project ID explanation"
assert "Jira Key" in help_text, "Help content missing Jira Key explanation"
# ---- Help text content ----------------------------------------------------
def test_project_id_help_content(dialog):
"""Project ID help must explain what it is, where to find it, example, and common mistake."""
from cowork_local.i18n import tr
text = tr("connectors.jira_kb_project_id_help")
assert "cowork-local" in text.lower() or "Cowork" in text, "Missing example"
# Must warn against entering Jira keys
lower = text.lower()
assert "jira" in lower and ("key" in lower or "issue" in lower), \
"Missing common mistake warning about Jira keys"
def test_jira_key_help_content(dialog):
"""Jira Key help must include the ABC-123 → ABC example."""
from cowork_local.i18n import tr
text = tr("connectors.jira_kb_jira_key_help")
assert "ABC-123" in text, "Missing ABC-123 example"
assert "ABC" in text, "Missing ABC extraction example"
def test_jira_key_help_warns_against_issue_key(dialog):
"""Jira Key help must explicitly warn not to enter ABC-123."""
from cowork_local.i18n import tr
text = tr("connectors.jira_kb_jira_key_help")
lower = text.lower()
# Should contain a warning like "Do not enter ABC-123" or "Không nhập ABC-123"
assert "abc-123" in lower, "Missing warning about entering issue key format"
# ---- Validation -----------------------------------------------------------
def test_validation_shows_on_issue_key_pattern(dialog):
"""Typing 'proj:ABC-123' should show the validation warning."""
dlg = dialog
dlg.show()
dlg.project_mapping.setText("myproject:ABC-123")
assert not dlg.mapping_validation.isHidden(), \
"Validation hint should be shown when Issue Key pattern detected"
assert dlg.mapping_validation.text(), "Validation hint should have text"
def test_validation_hides_on_correct_input(dialog):
"""Typing 'proj:ABC' should NOT show the validation warning."""
dlg = dialog
dlg.show()
dlg.project_mapping.setText("myproject:ABC")
assert dlg.mapping_validation.isHidden(), \
"Validation hint should be hidden for correct Jira Key format"
def test_validation_hides_on_empty(dialog):
"""Empty input should not show validation warning."""
dlg = dialog
dlg.show()
dlg.project_mapping.setText("")
assert dlg.mapping_validation.isHidden(), \
"Validation hint should be hidden on empty input"
def test_validation_multiple_mappings(dialog):
"""Validation should detect issue key pattern even in multi-mapping strings."""
dlg = dialog
dlg.show()
dlg.project_mapping.setText("proj-a:ALPHA, proj-b:DEF-456")
assert not dlg.mapping_validation.isHidden(), \
"Validation should trigger when any mapping contains an Issue Key pattern"
# ---- Existing behavior unchanged ------------------------------------------
def test_save_still_works(dialog):
"""Saving with valid mapping still produces correct config structure."""
dlg = dialog
dlg.url.setText("https://example.atlassian.net")
dlg.email.setText("user@example.com")
dlg.token.setText("test-token")
dlg.project_mapping.setText("myproject:MYKEY")
dlg.kb_enabled.setChecked(True)
dlg._save()
jira_kb = dlg.ctx.config.data.get("jira_knowledge", {})
assert jira_kb["enabled"] is True
assert jira_kb["projects"] == {"myproject": "MYKEY"}
def test_sync_button_present(dialog):
"""Sync Now button must still exist and be functional."""
dlg = dialog
assert dlg.sync_btn is not None
assert dlg.sync_btn.text(), "Sync button should have text"
# ---- Accessibility --------------------------------------------------------
def test_help_icon_cursor(dialog):
"""Help button should be a QToolButton (clickable by nature)."""
from PySide6.QtWidgets import QToolButton
dlg = dialog
help_icons = dlg.findChildren(QToolButton)
assert help_icons, "No help button found"
# QToolButton is inherently clickable, no need for cursor check
assert help_icons[0].text() == "?", "Help button should display '?' text"
# ---- i18n keys exist for all three languages ------------------------------
@pytest.mark.parametrize("lang", ["en", "vi", "ja"])
def test_i18n_keys_exist(lang):
"""All Jira KB help keys must have translations for en, vi, ja."""
from cowork_local.i18n import STRINGS
required_keys = [
"connectors.jira_kb_section",
"connectors.jira_kb_enable",
"connectors.jira_kb_mapping_label",
"connectors.jira_kb_project_id_title",
"connectors.jira_kb_jira_key_title",
"connectors.jira_kb_project_id_help",
"connectors.jira_kb_jira_key_help",
"connectors.jira_kb_validation_issue_key",
"connectors.jira_kb_sync_now",
"connectors.jira_kb_not_configured",
"connectors.jira_kb_disabled",
"connectors.jira_kb_syncing",
]
for key in required_keys:
assert key in STRINGS, f"Missing i18n key: {key}"
entry = STRINGS[key]
assert lang in entry, f"Missing '{lang}' translation for key: {key}"
assert entry[lang], f"Empty '{lang}' translation for key: {key}"