diff --git a/qutebrowser/components/misccommands.py b/qutebrowser/components/misccommands.py index b4eaa55d1..290964fa0 100644 --- a/qutebrowser/components/misccommands.py +++ b/qutebrowser/components/misccommands.py @@ -322,16 +322,23 @@ def debug_webaction(tab: apitypes.Tab, action: str, count: int = 1) -> None: @cmdutils.register() @cmdutils.argument('tab', value=cmdutils.Value.count_tab) -def tab_mute(tab: Optional[apitypes.Tab]) -> None: +@cmdutils.argument('mute', choices=['true', 'false']) +def tab_mute(tab: Optional[apitypes.Tab], mute: str = None) -> None: """Mute/Unmute the current/[count]th tab. Args: count: The tab index to mute or unmute, or None + mute: The mute setting to force : 'true' to mute, 'false' to unmute, omit to toggle. """ if tab is None: return try: - tab.audio.set_muted(not tab.audio.is_muted(), override=True) + if mute == 'true': + tab.audio.set_muted(True, override=True) + elif mute == 'false': + tab.audio.set_muted(False, override=True) + else: + tab.audio.set_muted(not tab.audio.is_muted(), override=True) except apitypes.WebTabError as e: raise cmdutils.CommandError(e) diff --git a/tests/helpers/stubs.py b/tests/helpers/stubs.py index 50528ee8b..75f86ee54 100644 --- a/tests/helpers/stubs.py +++ b/tests/helpers/stubs.py @@ -225,8 +225,16 @@ class FakeWebTabHistory(browsertab.AbstractHistory): class FakeWebTabAudio(browsertab.AbstractAudio): + def __init__(self, tab): + super().__init__(tab) + self._is_muted = False + def is_muted(self): - return False + return self._is_muted + + def set_muted(self, muted: bool, override: bool = False) -> None: + """Set muted state.""" + self._is_muted = muted def is_recently_audible(self): return False diff --git a/tests/unit/components/test_misccommands.py b/tests/unit/components/test_misccommands.py index 4f541b588..5c4dfae72 100644 --- a/tests/unit/components/test_misccommands.py +++ b/tests/unit/components/test_misccommands.py @@ -77,3 +77,19 @@ def test_debug_trace_no_hunter(monkeypatch): with pytest.raises(cmdutils.CommandError, match="You need to install " "'hunter' to use this command!"): misccommands.debug_trace() + + +@pytest.mark.parametrize("initial_muted,mute_arg,expected_muted", [ + (False, None, True), # Toggle: Unmuted → muted + (True, None, False), # Toggle: Muted → unmuted + (False, 'true', True), # Force mute + (True, 'true', True), # Force mute (idempotent) + (False, 'false', False), # Force unmute (idempotent) + (True, 'false', False), # Force unmute +]) +def test_tab_mute(fake_web_tab, initial_muted, mute_arg, expected_muted): + """Test tab_mute with different states and parameters.""" + tab = fake_web_tab() + tab.audio.set_muted(initial_muted) + misccommands.tab_mute(tab, mute=mute_arg) + assert tab.audio.is_muted() == expected_muted