1
|
# SPDX-License-Identifier: CC0-1.0
|
2
|
|
3
|
"""
|
4
|
Haketilo unit tests - repository querying
|
5
|
"""
|
6
|
|
7
|
# This file is part of Haketilo
|
8
|
#
|
9
|
# Copyright (C) 2022 Wojtek Kosior <koszko@koszko.org>
|
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 ..extension_crafting import ExtraHTML
|
24
|
from ..script_loader import load_script
|
25
|
from .utils import *
|
26
|
|
27
|
repo_urls = [f'https://hydril.la/{s}' for s in ('', '1/', '2/', '3/', '4/')]
|
28
|
|
29
|
queried_url = 'https://example_a.com/something'
|
30
|
|
31
|
def setup_view(execute_in_page, repo_urls, tab={'id': 0}):
|
32
|
execute_in_page(mock_cacher_code)
|
33
|
|
34
|
execute_in_page(load_script('html/repo_query.js'))
|
35
|
execute_in_page(
|
36
|
'''
|
37
|
const repo_proms = arguments[0].map(url => haketilodb.set_repo(url));
|
38
|
|
39
|
const cb_calls = [];
|
40
|
const view = new RepoQueryView(arguments[1],
|
41
|
() => cb_calls.push("show"),
|
42
|
() => cb_calls.push("hide"));
|
43
|
document.body.append(view.main_div);
|
44
|
const shw = slice => [cb_calls.slice(slice || 0), view.shown];
|
45
|
|
46
|
returnval(Promise.all(repo_proms));
|
47
|
''',
|
48
|
repo_urls, tab)
|
49
|
|
50
|
repo_query_ext_data = {
|
51
|
'background_script': broker_js,
|
52
|
'extra_html': ExtraHTML('html/repo_query.html', {}),
|
53
|
'navigate_to': 'html/repo_query.html'
|
54
|
}
|
55
|
|
56
|
@pytest.mark.ext_data(repo_query_ext_data)
|
57
|
@pytest.mark.usefixtures('webextension')
|
58
|
def test_repo_query_normal_usage(driver, execute_in_page):
|
59
|
"""
|
60
|
Test of using the repo query view to browse results from repository and to
|
61
|
start installation.
|
62
|
"""
|
63
|
setup_view(execute_in_page, repo_urls)
|
64
|
|
65
|
assert execute_in_page('returnval(shw());') == [[], False]
|
66
|
|
67
|
execute_in_page('view.show(arguments[0]);', queried_url)
|
68
|
|
69
|
assert execute_in_page('returnval(shw());') == [['show'], True]
|
70
|
|
71
|
def get_repo_entries(driver):
|
72
|
return execute_in_page(
|
73
|
f'returnval((view.repo_entries || []).map({nodes_props_code}));'
|
74
|
)
|
75
|
|
76
|
repo_entries = WebDriverWait(driver, 10).until(get_repo_entries)
|
77
|
|
78
|
assert len(repo_urls) == len(repo_entries)
|
79
|
|
80
|
for url, entry in reversed(list(zip(repo_urls, repo_entries))):
|
81
|
assert url in entry['main_li'].text
|
82
|
|
83
|
but_ids = ('show_results_but', 'hide_results_but')
|
84
|
for but_idx in (0, 1, 0):
|
85
|
assert bool(but_idx) == entry['list_container'].is_displayed()
|
86
|
|
87
|
assert not entry[but_ids[1 - but_idx]].is_displayed()
|
88
|
|
89
|
entry[but_ids[but_idx]].click()
|
90
|
|
91
|
def get_mapping_entries(driver):
|
92
|
return execute_in_page(
|
93
|
f'''{{
|
94
|
const result_entries = (view.repo_entries[0].result_entries || []);
|
95
|
returnval(result_entries.map({nodes_props_code}));
|
96
|
}}''')
|
97
|
|
98
|
mapping_entries = WebDriverWait(driver, 10).until(get_mapping_entries)
|
99
|
|
100
|
assert len(mapping_entries) == 3
|
101
|
|
102
|
expected_names = ['MAPPING-ABCD', 'MAPPING-ABCD-DEFG-GHIJ', 'MAPPING-A']
|
103
|
|
104
|
for name, entry in zip(expected_names, mapping_entries):
|
105
|
assert entry['mapping_name'].text == name
|
106
|
assert entry['mapping_id'].text == f'{name.lower()}-2022.5.11'
|
107
|
|
108
|
containers = execute_in_page(
|
109
|
'''{
|
110
|
const reductor = (acc, k) => Object.assign(acc, {[k]: view[k]});
|
111
|
returnval(container_ids.reduce(reductor, {}));
|
112
|
}''')
|
113
|
|
114
|
for id, container in containers.items():
|
115
|
assert (id == 'repos_list_container') == container.is_displayed()
|
116
|
|
117
|
entry['install_but'].click()
|
118
|
|
119
|
for id, container in containers.items():
|
120
|
assert (id == 'install_view_container') == container.is_displayed()
|
121
|
|
122
|
execute_in_page('returnval(view.install_view.cancel_but);').click()
|
123
|
|
124
|
for id, container in containers.items():
|
125
|
assert (id == 'repos_list_container') == container.is_displayed()
|
126
|
|
127
|
assert execute_in_page('returnval(shw());') == [['show'], True]
|
128
|
execute_in_page('returnval(view.cancel_but);').click()
|
129
|
assert execute_in_page('returnval(shw());') == [['show', 'hide'], False]
|
130
|
|
131
|
@pytest.mark.ext_data(repo_query_ext_data)
|
132
|
@pytest.mark.usefixtures('webextension')
|
133
|
@pytest.mark.parametrize('message', [
|
134
|
'browsing_for',
|
135
|
'no_repos',
|
136
|
'private_mode',
|
137
|
'failure_to_communicate',
|
138
|
'HTTP_code',
|
139
|
'invalid_JSON',
|
140
|
'newer_API_version',
|
141
|
'invalid_response_format',
|
142
|
'querying_repo',
|
143
|
'no_results'
|
144
|
])
|
145
|
def test_repo_query_messages(driver, execute_in_page, message):
|
146
|
"""
|
147
|
Test of loading and error messages shown in parts of the repo query view.
|
148
|
"""
|
149
|
def has_msg(message, elem=None):
|
150
|
def has_msg_and_is_visible(dummy_driver):
|
151
|
if elem:
|
152
|
return elem.is_displayed() and message in elem.text
|
153
|
else:
|
154
|
return message in driver.page_source
|
155
|
return has_msg_and_is_visible
|
156
|
|
157
|
def show_and_wait_for_repo_entry():
|
158
|
execute_in_page('view.show(arguments[0]);', queried_url)
|
159
|
done = lambda d: execute_in_page('returnval(!!view.repo_entries);')
|
160
|
WebDriverWait(driver, 10).until(done)
|
161
|
execute_in_page(
|
162
|
'''
|
163
|
if (view.repo_entries.length > 0)
|
164
|
view.repo_entries[0].show_results_but.click();
|
165
|
''')
|
166
|
|
167
|
if message == 'browsing_for':
|
168
|
setup_view(execute_in_page, [])
|
169
|
show_and_wait_for_repo_entry()
|
170
|
|
171
|
elem = execute_in_page('returnval(view.url_span.parentNode);')
|
172
|
assert has_msg(f'Browsing custom resources for: {queried_url}', elem)(0)
|
173
|
elif message == 'no_repos':
|
174
|
setup_view(execute_in_page, [])
|
175
|
show_and_wait_for_repo_entry()
|
176
|
|
177
|
elem = execute_in_page('returnval(view.repos_list);')
|
178
|
assert has_msg('You have no repositories configured :(', elem)(0)
|
179
|
elif message == 'private_mode':
|
180
|
setup_view(execute_in_page, repo_urls, tab={'id': 0, 'incognito': True})
|
181
|
show_and_wait_for_repo_entry()
|
182
|
|
183
|
elem = execute_in_page('returnval(view.top_text);')
|
184
|
assert has_msg('when in Private Browsing mode', elem)(0)
|
185
|
elif message == 'failure_to_communicate':
|
186
|
setup_view(execute_in_page, repo_urls)
|
187
|
execute_in_page(
|
188
|
'''
|
189
|
window.mock_cacher_fetch =
|
190
|
() => {throw new Error("Something happened :o")};
|
191
|
''')
|
192
|
show_and_wait_for_repo_entry()
|
193
|
|
194
|
elem = execute_in_page('returnval(view.repo_entries[0].info_div);')
|
195
|
done = has_msg('Failure to communicate with repository :(', elem)
|
196
|
WebDriverWait(driver, 10).until(done)
|
197
|
elif message == 'HTTP_code':
|
198
|
setup_view(execute_in_page, repo_urls)
|
199
|
execute_in_page(
|
200
|
'''
|
201
|
const response = new Response("", {status: 405});
|
202
|
window.mock_cacher_fetch = () => Promise.resolve(response);
|
203
|
''')
|
204
|
show_and_wait_for_repo_entry()
|
205
|
|
206
|
elem = execute_in_page('returnval(view.repo_entries[0].info_div);')
|
207
|
done = has_msg('Repository sent HTTP code 405 :(', elem)
|
208
|
WebDriverWait(driver, 10).until(done)
|
209
|
elif message == 'invalid_JSON':
|
210
|
setup_view(execute_in_page, repo_urls)
|
211
|
execute_in_page(
|
212
|
'''
|
213
|
const response = new Response("sth", {status: 200});
|
214
|
window.mock_cacher_fetch = () => Promise.resolve(response);
|
215
|
''')
|
216
|
show_and_wait_for_repo_entry()
|
217
|
|
218
|
elem = execute_in_page('returnval(view.repo_entries[0].info_div);')
|
219
|
done = has_msg("Repository's response is not valid JSON :(", elem)
|
220
|
WebDriverWait(driver, 10).until(done)
|
221
|
elif message == 'newer_API_version':
|
222
|
setup_view(execute_in_page, repo_urls)
|
223
|
execute_in_page(
|
224
|
'''
|
225
|
const newer_schema_url =
|
226
|
"https://hydrilla.koszko.org/schemas/api_query_result-255.2.1.schema.json";
|
227
|
const mocked_json_data = JSON.stringify({$schema: newer_schema_url});
|
228
|
const response = new Response(mocked_json_data, {status: 200});
|
229
|
window.mock_cacher_fetch = () => Promise.resolve(response);
|
230
|
''')
|
231
|
show_and_wait_for_repo_entry()
|
232
|
|
233
|
elem = execute_in_page('returnval(view.repo_entries[0].info_div);')
|
234
|
msg = 'Results were served using unsupported Hydrilla API version. You might need to update Haketilo.'
|
235
|
WebDriverWait(driver, 10).until(has_msg(msg, elem))
|
236
|
elif message == 'invalid_response_format':
|
237
|
setup_view(execute_in_page, repo_urls)
|
238
|
execute_in_page(
|
239
|
'''
|
240
|
window.mock_cacher_fetch = async function(...args) {
|
241
|
const response = await fetch(...args);
|
242
|
const json = await response.json();
|
243
|
|
244
|
/* $schema is no longer a string as it should be. */
|
245
|
json.$schema = null;
|
246
|
|
247
|
return new Response(JSON.stringify(json), {
|
248
|
status: response.status,
|
249
|
statusText: response.statusText,
|
250
|
headers: [...response.headers.entries()]
|
251
|
});
|
252
|
}
|
253
|
''')
|
254
|
show_and_wait_for_repo_entry()
|
255
|
|
256
|
elem = execute_in_page('returnval(view.repo_entries[0].info_div);')
|
257
|
msg = 'Results were served using a nonconforming response format.'
|
258
|
WebDriverWait(driver, 10).until(has_msg(msg, elem))
|
259
|
elif message == 'querying_repo':
|
260
|
setup_view(execute_in_page, repo_urls)
|
261
|
execute_in_page(
|
262
|
'window.mock_cacher_fetch = () => new Promise(cb => {});'
|
263
|
)
|
264
|
show_and_wait_for_repo_entry()
|
265
|
|
266
|
elem = execute_in_page('returnval(view.repo_entries[0].info_div);')
|
267
|
assert has_msg('Querying repository...', elem)(0)
|
268
|
elif message == 'no_results':
|
269
|
setup_view(execute_in_page, repo_urls)
|
270
|
execute_in_page(
|
271
|
'''
|
272
|
const schema_url =
|
273
|
"https://hydrilla.koszko.org/schemas/api_query_result-1.schema.json";
|
274
|
const mocked_json_data =
|
275
|
JSON.stringify({$schema: schema_url, mappings: []});
|
276
|
const response = new Response(mocked_json_data, {status: 200});
|
277
|
window.mock_cacher_fetch = () => Promise.resolve(response);
|
278
|
''')
|
279
|
show_and_wait_for_repo_entry()
|
280
|
|
281
|
elem = execute_in_page('returnval(view.repo_entries[0].info_div);')
|
282
|
WebDriverWait(driver, 10).until(has_msg('No results :(', elem))
|
283
|
else:
|
284
|
raise Exception('made a typo in test function params?')
|