220 lines
8.4 KiB
Python
220 lines
8.4 KiB
Python
from unittest.mock import Mock
|
|
|
|
import pytest
|
|
from PyQt6.QtCore import QObject, pyqtSignal
|
|
from PyQt6.QtGui import QTextDocument
|
|
from PyQt6.QtWidgets import QApplication
|
|
|
|
import room_widget
|
|
|
|
|
|
class PlayerSignals(QObject):
|
|
time_changed = pyqtSignal(int)
|
|
state_changed = pyqtSignal(bool, int)
|
|
|
|
|
|
@pytest.fixture
|
|
def room(qtbot, monkeypatch):
|
|
player = Mock(signals=PlayerSignals())
|
|
monkeypatch.setattr(room_widget, 'VLCSyncPlayer', lambda frame: player)
|
|
monkeypatch.setattr(room_widget.RoomWidget, '_play_reaction_sound', Mock())
|
|
widget = room_widget.RoomWidget()
|
|
widget.username = 'Me'
|
|
qtbot.addWidget(widget)
|
|
widget.resize(1050, 500)
|
|
widget.show()
|
|
return widget
|
|
|
|
|
|
@pytest.mark.parametrize('text', ["It's someone's & my <message>",
|
|
"It's at 1:23 & <b>literal</b>",
|
|
'line one\nline two', 'literal ' entity'])
|
|
def test_message_rendering(room, text):
|
|
room.add_chat_message("<b>O'Brien</b>", text, 0)
|
|
bubble = room.chat_content_layout.itemAt(0).widget()
|
|
doc = QTextDocument()
|
|
doc.setHtml(bubble.text_lbl.text())
|
|
assert doc.toPlainText() == text
|
|
if '1:23' in text:
|
|
assert 'href="seek:1:23"' in bubble.text_lbl.text()
|
|
|
|
|
|
def test_bubbles_do_not_shrink_or_clip_when_overflowing(room, qtbot):
|
|
text = 'A wrapped message with several words. ' * 8
|
|
room.add_chat_message('Other', text, 0)
|
|
qtbot.wait(100)
|
|
first = room.chat_content_layout.itemAt(0).widget()
|
|
initial_height = first.height()
|
|
for i in range(35):
|
|
room.add_chat_message('Me' if i % 2 else 'Other', text, 0)
|
|
qtbot.wait(200)
|
|
assert room.chat_messages.verticalScrollBar().maximum() > 0
|
|
assert first.height() >= initial_height
|
|
for width in (220, 450, 280):
|
|
room.splitter.setSizes([room.width() - width, width])
|
|
qtbot.wait(100)
|
|
for i in range(room.chat_content_layout.count()):
|
|
bubble = room.chat_content_layout.itemAt(i).widget()
|
|
label = bubble.text_lbl
|
|
assert label.height() >= label.heightForWidth(label.width())
|
|
assert bubble.bubble.rect().contains(label.geometry())
|
|
|
|
|
|
def test_unread_alert_and_focus_clear(room, qtbot, monkeypatch):
|
|
alert = Mock()
|
|
monkeypatch.setattr(QApplication, 'alert', alert)
|
|
room.activateWindow()
|
|
room.setFocus()
|
|
qtbot.wait(50)
|
|
room.add_chat_message('Other', 'hello', 0)
|
|
assert room._unread_messages == 1
|
|
alert.assert_called_once()
|
|
room.add_chat_message('Me', 'reply', 0)
|
|
assert room._unread_messages == 1
|
|
room.chat_input.setFocus()
|
|
qtbot.wait(50)
|
|
assert room._unread_messages == 0
|
|
room.add_chat_message('Other', 'focused', 0)
|
|
assert room._unread_messages == 0
|
|
room.chat_container.hide()
|
|
room.add_chat_message('Other', 'hidden', 0)
|
|
assert room._unread_messages == 1
|
|
room.clear_chat()
|
|
assert room._unread_messages == 0
|
|
|
|
|
|
def test_popout_focus_and_wrapping(room, qtbot, monkeypatch):
|
|
monkeypatch.setattr(QApplication, 'alert', Mock())
|
|
room.popout_chat()
|
|
popout = room.popout_window
|
|
qtbot.addWidget(popout)
|
|
popout.activateWindow()
|
|
room.chat_input.setFocus()
|
|
qtbot.wait(100)
|
|
room.add_chat_message('Other', 'Wrapped popout text ' * 40, 0)
|
|
qtbot.wait(100)
|
|
assert room._unread_messages == 0
|
|
bubble = room.chat_content_layout.itemAt(0).widget()
|
|
assert bubble.text_lbl.height() >= bubble.text_lbl.heightForWidth(bubble.text_lbl.width())
|
|
room.activateWindow()
|
|
room.setFocus()
|
|
qtbot.wait(100)
|
|
room.add_chat_message('Other', 'Background popout', 0)
|
|
assert room._unread_messages == 1
|
|
popout.close()
|
|
|
|
|
|
def test_scrolling_preserves_position_and_counts_unread(room, qtbot):
|
|
for i in range(30):
|
|
room.add_chat_message('Other', f'Message {i}: ' + 'wrapped words ' * 10, 0)
|
|
qtbot.wait(150)
|
|
bar = room.chat_messages.verticalScrollBar()
|
|
assert bar.value() == bar.maximum()
|
|
bar.setValue(100)
|
|
qtbot.wait(30)
|
|
position = bar.value()
|
|
room.add_chat_message('Other', 'First unread message', 0)
|
|
room.add_chat_message('Other', 'Second unread message', 0)
|
|
room.add_system_message('Someone paused')
|
|
qtbot.wait(150)
|
|
assert bar.value() == position
|
|
assert room._pending_chat_messages == 2
|
|
assert not room.chat_jump_btn.isHidden()
|
|
assert room._unread_divider is not None
|
|
room.chat_input.setFocus()
|
|
assert room._pending_chat_messages == 2
|
|
room.jump_to_latest()
|
|
qtbot.wait(150)
|
|
assert bar.value() == bar.maximum()
|
|
assert room.chat_jump_btn.isHidden()
|
|
room.add_chat_message('Other', 'Follow latest', 0)
|
|
qtbot.wait(150)
|
|
assert bar.value() == bar.maximum()
|
|
assert room._pending_chat_messages == 0
|
|
|
|
|
|
def test_scroll_back_to_bottom_clears_pending(room, qtbot):
|
|
for i in range(20):
|
|
room.add_chat_message('Other', 'Words ' * 30, 0)
|
|
qtbot.wait(150)
|
|
bar = room.chat_messages.verticalScrollBar()
|
|
bar.setValue(0)
|
|
room.add_chat_message('Other', 'Unread', 0)
|
|
qtbot.wait(100)
|
|
bar.setValue(bar.maximum())
|
|
assert room._pending_chat_messages == 0
|
|
assert room._follow_chat
|
|
assert room.chat_jump_btn.isHidden()
|
|
room.clear_chat()
|
|
assert room._unread_divider is None
|
|
assert room.chat_content_layout.count() == 0
|
|
|
|
|
|
def test_ready_command_and_controls(room, qtbot):
|
|
with qtbot.waitSignal(room.ready_action_requested) as signal:
|
|
room.chat_input.setText('/ready')
|
|
room.send_chat()
|
|
assert signal.args == [{'type': 'ready_check', 'action': 'begin'}]
|
|
assert room.chat_input.text() == ''
|
|
state = {'active': True, 'id': 'check-1', 'requestedBy': 'Me', 'participants': [
|
|
{'username': 'Me', 'ready': False, 'connected': True},
|
|
{'username': "<b>O'Brien</b>", 'ready': True, 'connected': True}]}
|
|
room.update_ready_check(state)
|
|
assert not room.ready_panel.isHidden()
|
|
assert not room.ready_start_btn.isEnabled()
|
|
assert "<b>O'Brien</b>" in room.ready_users.text()
|
|
with qtbot.waitSignal(room.ready_action_requested) as signal:
|
|
room.ready_btn.click()
|
|
assert signal.args[0] == {'type': 'ready_check', 'action': 'vote', 'id': 'check-1', 'ready': True}
|
|
state['participants'][0]['ready'] = True
|
|
room.update_ready_check(state)
|
|
assert room.ready_start_btn.isEnabled()
|
|
with qtbot.waitSignal(room.ready_action_requested) as signal:
|
|
room.ready_start_btn.click()
|
|
assert signal.args[0]['action'] == 'start'
|
|
state['participants'][1]['connected'] = False
|
|
room.update_ready_check(state)
|
|
assert not room.ready_start_btn.isEnabled()
|
|
assert 'Reconnecting' in room.ready_users.text()
|
|
state['requestedBy'] = 'Other'
|
|
room.update_ready_check(state)
|
|
assert room.ready_start_btn.isHidden()
|
|
room.update_ready_check({'active': False})
|
|
assert room.ready_panel.isHidden()
|
|
|
|
|
|
def test_ready_panel_buttons_fit_styled_chat(room, qtbot):
|
|
from main import VlcSyncApp
|
|
VlcSyncApp.apply_stylesheet(room)
|
|
room.splitter.setSizes([750, 300])
|
|
room.update_ready_check({'active': True, 'id': 'layout', 'requestedBy': 'Me', 'participants': [
|
|
{'username': 'Me', 'ready': True, 'connected': True}]})
|
|
qtbot.wait(100)
|
|
for button in (room.ready_btn, room.ready_start_btn, room.ready_cancel_btn):
|
|
assert button.width() >= button.fontMetrics().horizontalAdvance(button.text()) + 20
|
|
room.update_connection_status(False)
|
|
room.update_ready_check(room._ready_check)
|
|
assert not room.ready_start_btn.isEnabled()
|
|
assert not room.ready_btn.isEnabled()
|
|
|
|
|
|
def test_app_wires_commands_to_websocket_and_incoming_panels(room, qtbot, monkeypatch):
|
|
import main
|
|
from sync_client import SyncClientThread
|
|
client = SyncClientThread()
|
|
client.send_message = Mock()
|
|
monkeypatch.setattr(main, 'SyncClientThread', lambda url: client)
|
|
app = main.VlcSyncApp()
|
|
qtbot.addWidget(app)
|
|
for command, expected in [('/ready', {'type': 'ready_check', 'action': 'begin'}),
|
|
('/ko', {'type': 'reaction', 'kind': 'ko'}),
|
|
('/bell', {'type': 'reaction', 'kind': 'bell'})]:
|
|
app.room_widget.chat_input.setText(command)
|
|
app.room_widget.send_chat()
|
|
client.send_message.assert_called_with(expected)
|
|
state = {'type': 'ready_check', 'active': True, 'id': 'wired', 'requestedBy': 'Me',
|
|
'participants': [{'username': 'Me', 'ready': False, 'connected': True}]}
|
|
client._handle_message(state)
|
|
assert app.room_widget._ready_check['id'] == 'wired'
|
|
assert not app.room_widget.ready_panel.isHidden()
|