1
|
# SPDX-License-Identifier: CC0-1.0
|
2
|
|
3
|
"""
|
4
|
Haketilo unit tests - message broadcasting
|
5
|
"""
|
6
|
|
7
|
# This file is part of Haketilo
|
8
|
#
|
9
|
# Copyright (C) 2021, Wojtek Kosior
|
10
|
#
|
11
|
# This program is free software: you can redistribute it and/or modify
|
12
|
# it under the terms of the CC0 1.0 Universal License as published by
|
13
|
# the Creative Commons Corporation.
|
14
|
#
|
15
|
# This program is distributed in the hope that it will be useful,
|
16
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
17
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
18
|
# CC0 1.0 Universal License for more details.
|
19
|
|
20
|
import pytest
|
21
|
from selenium.webdriver.support.ui import WebDriverWait
|
22
|
|
23
|
from ..script_loader import load_script
|
24
|
from .utils import broker_js
|
25
|
|
26
|
test_page_html = '''
|
27
|
<!DOCTYPE html>
|
28
|
<script src="/testpage.js"></script>
|
29
|
<h2>d0 (channel `somebodyoncetoldme`)</h2>
|
30
|
<div id="d0"></div>
|
31
|
<h2>d1 (channel `worldisgonnarollme`)</h2>
|
32
|
<div id="d1"></div>
|
33
|
<h2>d2 (both channels)</h2>
|
34
|
<div id="d2"></div>
|
35
|
'''
|
36
|
|
37
|
@pytest.mark.ext_data({
|
38
|
'background_script': broker_js,
|
39
|
'test_page': test_page_html,
|
40
|
'extra_files': {
|
41
|
'testpage.js': lambda: load_script('common/broadcast.js')
|
42
|
}
|
43
|
})
|
44
|
@pytest.mark.usefixtures('webextension')
|
45
|
def test_broadcast(driver, execute_in_page, wait_elem_text):
|
46
|
"""
|
47
|
A test that verifies the broadcasting system based on WebExtension messaging
|
48
|
API and implemented in `background/broadcast_broker.js` and
|
49
|
`common/broadcast.js` works correctly.
|
50
|
"""
|
51
|
# The broadcast facility is meant to enable message distribution between
|
52
|
# multiple contexts (e.g. different tabs/windows). Let's open the same
|
53
|
# extension's test page in a second window.
|
54
|
driver.execute_script(
|
55
|
'''
|
56
|
window.open(window.location.href, "_blank");
|
57
|
window.open(window.location.href, "_blank");
|
58
|
''')
|
59
|
WebDriverWait(driver, 10).until(lambda d: len(d.window_handles) == 3)
|
60
|
windows = [*driver.window_handles]
|
61
|
|
62
|
# Let's first test if a simple message can be successfully broadcasted
|
63
|
driver.switch_to.window(windows[0])
|
64
|
execute_in_page(
|
65
|
'''
|
66
|
const divs = [0, 1, 2].map(n => document.getElementById("d" + n));
|
67
|
let appender = n => (t => divs[n].append("\\n" + `[${t[0]}, ${t[1]}]`));
|
68
|
let listener0 = listener_connection(appender(0));
|
69
|
subscribe(listener0, "somebodyoncetoldme");
|
70
|
''')
|
71
|
|
72
|
driver.switch_to.window(windows[1])
|
73
|
execute_in_page(
|
74
|
'''
|
75
|
let sender0 = sender_connection();
|
76
|
out(sender0, "somebodyoncetoldme", "iaintthesharpesttool");
|
77
|
''')
|
78
|
|
79
|
driver.switch_to.window(windows[0])
|
80
|
wait_elem_text('d0', '[somebodyoncetoldme, iaintthesharpesttool]')
|
81
|
|
82
|
# Let's add 2 more listeners
|
83
|
driver.switch_to.window(windows[0])
|
84
|
execute_in_page(
|
85
|
'''
|
86
|
let listener1 = listener_connection(appender(1));
|
87
|
subscribe(listener1, "worldisgonnarollme");
|
88
|
let listener2 = listener_connection(appender(2));
|
89
|
subscribe(listener2, "worldisgonnarollme");
|
90
|
subscribe(listener2, "somebodyoncetoldme");
|
91
|
''')
|
92
|
|
93
|
# Let's send one message to one channel and one to the other. Verify they
|
94
|
# were received by the rght listeners.
|
95
|
driver.switch_to.window(windows[1])
|
96
|
execute_in_page(
|
97
|
'''
|
98
|
out(sender0, "somebodyoncetoldme", "intheshed");
|
99
|
out(sender0, "worldisgonnarollme", "shewaslooking");
|
100
|
''')
|
101
|
|
102
|
driver.switch_to.window(windows[0])
|
103
|
wait_elem_text('d0', 'intheshed')
|
104
|
wait_elem_text('d1', 'shewaslooking')
|
105
|
wait_elem_text('d2', 'intheshed')
|
106
|
wait_elem_text('d2', 'shewaslooking')
|
107
|
|
108
|
text = execute_in_page('returnval(divs[0].innerText);')
|
109
|
assert 'shewaslooking' not in text
|
110
|
text = execute_in_page('returnval(divs[1].innerText);')
|
111
|
assert 'intheshed' not in text
|
112
|
|
113
|
# Let's create a second sender in third window and use it to send messages
|
114
|
# with the 'prepare' feature.
|
115
|
driver.switch_to.window(windows[2])
|
116
|
execute_in_page(
|
117
|
'''
|
118
|
let sender1 = sender_connection();
|
119
|
prepare(sender1, "somebodyoncetoldme", "kindadumb");
|
120
|
out(sender1, "worldisgonnarollme", "withherfinger");
|
121
|
''')
|
122
|
|
123
|
driver.switch_to.window(windows[0])
|
124
|
wait_elem_text('d1', 'withherfinger')
|
125
|
text = execute_in_page('returnval(divs[0].innerText);')
|
126
|
assert 'kindadumb' not in text
|
127
|
|
128
|
driver.switch_to.window(windows[2])
|
129
|
execute_in_page('flush(sender1);')
|
130
|
|
131
|
driver.switch_to.window(windows[0])
|
132
|
wait_elem_text('d0', 'kindadumb')
|
133
|
|
134
|
# Let's verify that prepare()'d messages are properly discarded when
|
135
|
# discard() is called.
|
136
|
driver.switch_to.window(windows[2])
|
137
|
execute_in_page(
|
138
|
'''
|
139
|
prepare(sender1, "somebodyoncetoldme", "andherthumb");
|
140
|
discard(sender1);
|
141
|
prepare(sender1, "somebodyoncetoldme", "andhermiddlefinger");
|
142
|
flush(sender1);
|
143
|
''')
|
144
|
|
145
|
driver.switch_to.window(windows[0])
|
146
|
wait_elem_text('d0', 'andhermiddlefinger')
|
147
|
text = execute_in_page('returnval(divs[0].innerText);')
|
148
|
assert 'andherthumb' not in text
|
149
|
|
150
|
# Let's verify prepare()'d messages are properly auto-flushed when the other
|
151
|
# end of the connection gets killed (e.g. because browser tab gets closed).
|
152
|
driver.switch_to.window(windows[2])
|
153
|
execute_in_page(
|
154
|
'''
|
155
|
prepare(sender1, "worldisgonnarollme", "intheshape", 500);
|
156
|
''')
|
157
|
driver.close()
|
158
|
|
159
|
driver.switch_to.window(windows[0])
|
160
|
wait_elem_text('d2', 'intheshape')
|
161
|
|
162
|
# Verify listener's connection gets closed properly.
|
163
|
execute_in_page('close(listener0); close(listener1);')
|
164
|
|
165
|
driver.switch_to.window(windows[1])
|
166
|
execute_in_page('out(sender0, "worldisgonnarollme", "ofanL");')
|
167
|
execute_in_page('out(sender0, "somebodyoncetoldme", "forehead");')
|
168
|
|
169
|
driver.switch_to.window(windows[0])
|
170
|
wait_elem_text('d2', 'ofanL')
|
171
|
wait_elem_text('d2', 'forehead')
|
172
|
for i in (0, 1):
|
173
|
text = execute_in_page('returnval(divs[arguments[0]].innerText);', i)
|
174
|
assert 'ofanL' not in text
|
175
|
assert 'forehead' not in text
|