Revision 42fe4405
Added by koszko over 1 year ago
| html/popup.html | ||
|---|---|---|
| 1 |
<!DOCTYPE html> |
|
| 2 |
<!-- |
|
| 3 |
SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0 |
|
| 4 |
|
|
| 5 |
Show details of how Haketilo handled given page and allow querying |
|
| 6 |
repositories for custom scripts. |
|
| 7 |
|
|
| 8 |
This file is part of Haketilo. |
|
| 9 |
|
|
| 10 |
Copyright (C) 2022 Wojtek Kosior <koszko@koszko.org> |
|
| 11 |
|
|
| 12 |
File is dual-licensed. You can choose either GPLv3+, CC BY-SA or both. |
|
| 13 |
|
|
| 14 |
This program is free software: you can redistribute it and/or modify |
|
| 15 |
it under the terms of the GNU General Public License as published by |
|
| 16 |
the Free Software Foundation, either version 3 of the License, or |
|
| 17 |
(at your option) any later version. |
|
| 18 |
|
|
| 19 |
This program is distributed in the hope that it will be useful, |
|
| 20 |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 21 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| 22 |
GNU General Public License for more details. |
|
| 23 |
|
|
| 24 |
You should have received a copy of the GNU General Public License |
|
| 25 |
along with this program. If not, see <https://www.gnu.org/licenses/>. |
|
| 26 |
|
|
| 27 |
I, Wojtek Kosior, thereby promise not to sue for violation of this file's |
|
| 28 |
licenses. Although I request that you do not make use of this code in a |
|
| 29 |
proprietary program, I am not going to enforce this in court. |
|
| 30 |
--> |
|
| 31 |
<html> |
|
| 32 |
<head> |
|
| 33 |
<meta charset="utf-8"/> |
|
| 34 |
<title>Haketilo popup</title> |
|
| 35 |
#LOADCSS html/reset.css |
|
| 36 |
#LOADCSS html/base.css |
|
| 37 |
#LOADCSS html/grid.css |
|
| 38 |
<style> |
|
| 39 |
#IF TEST |
|
| 40 |
html {
|
|
| 41 |
background-color: #444; |
|
| 42 |
} |
|
| 43 |
#ENDIF |
|
| 44 |
|
|
| 45 |
html, body {
|
|
| 46 |
width: 400px; |
|
| 47 |
overflow-x: hidden; |
|
| 48 |
overflow-y: auto; |
|
| 49 |
} |
|
| 50 |
|
|
| 51 |
#page_info_container {
|
|
| 52 |
padding: 0.4em; |
|
| 53 |
} |
|
| 54 |
|
|
| 55 |
#info_form, #unprivileged_page_info {
|
|
| 56 |
display: grid; |
|
| 57 |
grid-template-columns: auto; |
|
| 58 |
text-align: center; |
|
| 59 |
} |
|
| 60 |
|
|
| 61 |
#info_form * {
|
|
| 62 |
white-space: nowrap; |
|
| 63 |
text-overflow: ellipsis; |
|
| 64 |
overflow-x: hidden; |
|
| 65 |
} |
|
| 66 |
|
|
| 67 |
#info_form label {
|
|
| 68 |
padding-bottom: 0.2em; |
|
| 69 |
} |
|
| 70 |
#info_form label+span, .top_but_container {
|
|
| 71 |
padding-bottom: 0.5em; |
|
| 72 |
} |
|
| 73 |
</style> |
|
| 74 |
</head> |
|
| 75 |
<body> |
|
| 76 |
<!-- It contains just templates, we can include it at the top --> |
|
| 77 |
#INCLUDE html/repo_query.html |
|
| 78 |
<div id="page_info_container"> |
|
| 79 |
<div id="loading_info"> |
|
| 80 |
Loading page info... |
|
| 81 |
</div> |
|
| 82 |
<div id="info_form" class="hide"> |
|
| 83 |
<label>Page URL:</label> |
|
| 84 |
<span id="page_url"></span> |
|
| 85 |
<label id="privileged_page_info" class="hide">Privileged page</label> |
|
| 86 |
<div id="unprivileged_page_info" class="hide"> |
|
| 87 |
<label>Scripts blocked:</label> |
|
| 88 |
<span id="scripts_blocked"></span> |
|
| 89 |
<label>Injected payload:</label> |
|
| 90 |
<span id="injected_payload"></span> |
|
| 91 |
<label>Mapping used:</label> |
|
| 92 |
<span id="mapping_used"></span> |
|
| 93 |
</div> |
|
| 94 |
</div> |
|
| 95 |
<div class="text_center top_but_container"> |
|
| 96 |
<button id="search_resources_but" class="hide"> |
|
| 97 |
Search for custom resources |
|
| 98 |
</button> |
|
| 99 |
</div> |
|
| 100 |
<div class="text_center"> |
|
| 101 |
<button id="settings_but"> |
|
| 102 |
Open settings |
|
| 103 |
</button> |
|
| 104 |
</div> |
|
| 105 |
</div> |
|
| 106 |
<div id="repo_query_container" class="hide"> |
|
| 107 |
<!-- Repo query view will be dynamically inserted here. --> |
|
| 108 |
</div> |
|
| 109 |
#LOADJS html/popup.js |
|
| 110 |
</body> |
|
| 111 |
</html> |
|
| html/popup.js | ||
|---|---|---|
| 1 |
/** |
|
| 2 |
* This file is part of Haketilo. |
|
| 3 |
* |
|
| 4 |
* Function: Show details of how Haketilo handled given page, drive popup. |
|
| 5 |
* |
|
| 6 |
* Copyright (C) 2021,2022 Wojtek Kosior |
|
| 7 |
* |
|
| 8 |
* This program is free software: you can redistribute it and/or modify |
|
| 9 |
* it under the terms of the GNU General Public License as published by |
|
| 10 |
* the Free Software Foundation, either version 3 of the License, or |
|
| 11 |
* (at your option) any later version. |
|
| 12 |
* |
|
| 13 |
* This program is distributed in the hope that it will be useful, |
|
| 14 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 15 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| 16 |
* GNU General Public License for more details. |
|
| 17 |
* |
|
| 18 |
* As additional permission under GNU GPL version 3 section 7, you |
|
| 19 |
* may distribute forms of that code without the copy of the GNU |
|
| 20 |
* GPL normally required by section 4, provided you include this |
|
| 21 |
* license notice and, in case of non-source distribution, a URL |
|
| 22 |
* through which recipients can access the Corresponding Source. |
|
| 23 |
* If you modify file(s) with this exception, you may extend this |
|
| 24 |
* exception to your version of the file(s), but you are not |
|
| 25 |
* obligated to do so. If you do not wish to do so, delete this |
|
| 26 |
* exception statement from your version. |
|
| 27 |
* |
|
| 28 |
* As a special exception to the GPL, any HTML file which merely |
|
| 29 |
* makes function calls to this code, and for that purpose |
|
| 30 |
* includes it by reference shall be deemed a separate work for |
|
| 31 |
* copyright law purposes. If you modify this code, you may extend |
|
| 32 |
* this exception to your version of the code, but you are not |
|
| 33 |
* obligated to do so. If you do not wish to do so, delete this |
|
| 34 |
* exception statement from your version. |
|
| 35 |
* |
|
| 36 |
* You should have received a copy of the GNU General Public License |
|
| 37 |
* along with this program. If not, see <https://www.gnu.org/licenses/>. |
|
| 38 |
* |
|
| 39 |
* I, Wojtek Kosior, thereby promise not to sue for violation of this file's |
|
| 40 |
* license. Although I request that you do not make use of this code in a |
|
| 41 |
* proprietary program, I am not going to enforce this in court. |
|
| 42 |
*/ |
|
| 43 |
|
|
| 44 |
#FROM common/browser.js IMPORT browser |
|
| 45 |
#FROM common/misc.js IMPORT is_privileged_url |
|
| 46 |
#FROM html/DOM_helpers.js IMPORT by_id |
|
| 47 |
#FROM html/repo_query.js IMPORT RepoQueryView |
|
| 48 |
|
|
| 49 |
const tab_query = {currentWindow: true, active: true};
|
|
| 50 |
|
|
| 51 |
async function get_current_tab() {
|
|
| 52 |
#IF CHROMIUM |
|
| 53 |
const callback = (cb) => browser.tabs.query(tab_query, tab => cb(tab)); |
|
| 54 |
const promise = new Promise(callback); |
|
| 55 |
#ELIF MOZILLA |
|
| 56 |
const promise = browser.tabs.query(tab_query); |
|
| 57 |
#ENDIF |
|
| 58 |
|
|
| 59 |
try {
|
|
| 60 |
return (await promise)[0]; |
|
| 61 |
} catch(e) {
|
|
| 62 |
console.log(e); |
|
| 63 |
} |
|
| 64 |
} |
|
| 65 |
|
|
| 66 |
async function get_page_info(tab_id) {
|
|
| 67 |
return browser.tabs.sendMessage(tab_id, ["page_info"]); |
|
| 68 |
} |
|
| 69 |
|
|
| 70 |
function show_page_info(page_info) {
|
|
| 71 |
by_id("loading_info").remove();
|
|
| 72 |
by_id("info_form").classList.remove("hide");
|
|
| 73 |
by_id("page_url").innerText = page_info.url;
|
|
| 74 |
|
|
| 75 |
if (page_info.privileged) {
|
|
| 76 |
by_id("privileged_page_info").classList.remove("hide");
|
|
| 77 |
} else {
|
|
| 78 |
by_id("unprivileged_page_info").classList.remove("hide");
|
|
| 79 |
|
|
| 80 |
by_id("scripts_blocked").innerText = page_info.allow ? "no" : "yes";
|
|
| 81 |
|
|
| 82 |
by_id("injected_payload").innerText = page_info.payload ?
|
|
| 83 |
page_info.payload.identifier : "None"; |
|
| 84 |
|
|
| 85 |
const scripts_fate = page_info.allow ? "allowed" : "blocked"; |
|
| 86 |
|
|
| 87 |
if (page_info.mapping === "~allow") |
|
| 88 |
var mapping = `None (scripts ${scripts_fate} by a rule)`;
|
|
| 89 |
else if (page_info.mapping) |
|
| 90 |
var mapping = page_info.mapping; |
|
| 91 |
else |
|
| 92 |
var mapping = `None (scripts ${scripts_fate} by default policy)`;
|
|
| 93 |
by_id("mapping_used").innerText = mapping;
|
|
| 94 |
} |
|
| 95 |
} |
|
| 96 |
|
|
| 97 |
function repo_query_showing(show) {
|
|
| 98 |
for (const [id, i] of [["repo_query", 0], ["page_info", 1]]) |
|
| 99 |
by_id(`${id}_container`).classList[["add", "remove"][show ^ i]]("hide");
|
|
| 100 |
} |
|
| 101 |
|
|
| 102 |
function prepare_repo_query_view(tab_id, page_info) {
|
|
| 103 |
const repo_query_view = new RepoQueryView(tab_id, |
|
| 104 |
() => repo_query_showing(true), |
|
| 105 |
() => repo_query_showing(false)); |
|
| 106 |
by_id("repo_query_container").prepend(repo_query_view.main_div);
|
|
| 107 |
|
|
| 108 |
let search_cb = () => repo_query_view.show(page_info.url); |
|
| 109 |
search_cb = repo_query_view.when_hidden(search_cb); |
|
| 110 |
by_id("search_resources_but").addEventListener("click", search_cb);
|
|
| 111 |
by_id("search_resources_but").classList.remove("hide");
|
|
| 112 |
} |
|
| 113 |
|
|
| 114 |
async function main() {
|
|
| 115 |
const settings_opener = (e) => browser.runtime.openOptionsPage(); |
|
| 116 |
by_id("settings_but").addEventListener("click", settings_opener);
|
|
| 117 |
|
|
| 118 |
try {
|
|
| 119 |
var tab = await get_current_tab(); |
|
| 120 |
var tab_id = tab.id; |
|
| 121 |
|
|
| 122 |
if (is_privileged_url(tab.url)) |
|
| 123 |
var page_info = {privileged: true, url: tab.url};
|
|
| 124 |
else |
|
| 125 |
var page_info = await get_page_info(tab_id); |
|
| 126 |
} catch(e) {
|
|
| 127 |
console.error(e); |
|
| 128 |
} |
|
| 129 |
|
|
| 130 |
if (page_info) {
|
|
| 131 |
show_page_info(page_info); |
|
| 132 |
if (!page_info.privileged) |
|
| 133 |
prepare_repo_query_view(tab_id, page_info); |
|
| 134 |
} else {
|
|
| 135 |
by_id("loading_info").innerText =
|
|
| 136 |
"Page info not avaialable. Try reloading the page."; |
|
| 137 |
} |
|
| 138 |
} |
|
| 139 |
|
|
| 140 |
main(); |
|
| html/repo_query.html | ||
|---|---|---|
| 38 | 38 |
|
| 39 | 39 |
#LOADCSS html/reset.css |
| 40 | 40 |
#LOADCSS html/base.css |
| 41 |
#LOADCSS html/grid.css |
|
| 42 | 41 |
<style> |
| 43 | 42 |
.repo_query_top_text {
|
| 44 | 43 |
text-align: center; |
| 45 |
margin: 0.4em; |
|
| 44 |
padding: 0.4em; |
|
| 45 |
text-overflow: ellipsis; |
|
| 46 |
overflow: hidden; |
|
| 46 | 47 |
} |
| 47 | 48 |
.repo_queried_url {
|
| 48 | 49 |
text-decoration: underline; |
| 50 |
white-space: nowrap; |
|
| 49 | 51 |
} |
| 50 | 52 |
|
| 51 | 53 |
.repo_query_repo_li {
|
| ... | ... | |
| 77 | 79 |
flex: 1 1 auto; |
| 78 | 80 |
min-width: 0; |
| 79 | 81 |
} |
| 82 |
|
|
| 80 | 83 |
.repo_query_entry_info > * {
|
| 81 | 84 |
white-space: nowrap; |
| 82 | 85 |
overflow: hidden; |
| 83 | 86 |
text-overflow: ellipsis; |
| 87 |
padding-bottom: 0.1em; |
|
| 84 | 88 |
} |
| 85 | 89 |
.repo_query_entry button {
|
| 86 | 90 |
white-space: nowrap; |
| ... | ... | |
| 97 | 101 |
} |
| 98 | 102 |
</style> |
| 99 | 103 |
<template> |
| 100 |
<div id="repo_query" data-template="main_div" |
|
| 101 |
class="grid_1 repo_query_main_div"> |
|
| 104 |
<div id="repo_query" data-template="main_div" class="repo_query_main_div"> |
|
| 102 | 105 |
<div data-template="repos_list_container"> |
| 103 | 106 |
<div class="repo_query_top_text"> |
| 104 |
Browsing custom resources for |
|
| 105 |
<span data-template="url_span" class="repo_queried_url"></span>.
|
|
| 107 |
Browsing custom resources for:
|
|
| 108 |
<span data-template="url_span" class="repo_queried_url"></span> |
|
| 106 | 109 |
</div> |
| 107 | 110 |
<ul data-template="repos_list"></ul> |
| 108 | 111 |
<div class="repo_query_bottom_buttons"> |
| html/repo_query.js | ||
|---|---|---|
| 118 | 118 |
return; |
| 119 | 119 |
} |
| 120 | 120 |
|
| 121 |
this.info_span.remove(); |
|
| 122 |
this.results_list.classList.remove("hide");
|
|
| 123 |
|
|
| 124 | 121 |
this.result_entries = results.map(ref => new ResultEntry(this, ref)); |
| 125 | 122 |
|
| 126 |
const to_append = this.result_entries.length > 0 ?
|
|
| 127 |
this.result_entries.map(re => re.main_li) :
|
|
| 128 |
["No results :("];
|
|
| 123 |
if (this.result_entries.length > 0) {
|
|
| 124 |
this.results_list.classList.remove("hide");
|
|
| 125 |
this.info_span.remove();
|
|
| 129 | 126 |
|
| 130 |
this.results_list.append(...to_append); |
|
| 127 |
const to_append = this.result_entries.map(re => re.main_li); |
|
| 128 |
this.results_list.append(...to_append); |
|
| 129 |
} else {
|
|
| 130 |
this.info_span.innerText = "No results :(";
|
|
| 131 |
} |
|
| 131 | 132 |
} |
| 132 | 133 |
|
| 133 | 134 |
let show_results = () => {
|
| test/extension_crafting.py | ||
|---|---|---|
| 63 | 63 |
], |
| 64 | 64 |
'content_security_policy': "object-src 'none'; script-src 'self' https://serve.scrip.ts;", |
| 65 | 65 |
'web_accessible_resources': ['testpage.html'], |
| 66 |
'options_ui': {
|
|
| 67 |
'page': 'testpage.html', |
|
| 68 |
'open_in_tab': True |
|
| 69 |
}, |
|
| 66 | 70 |
'background': {
|
| 67 | 71 |
'persistent': True, |
| 68 | 72 |
'scripts': ['__open_test_page.js', 'background.js'] |
| test/unit/conftest.py | ||
|---|---|---|
| 59 | 59 |
nav_target = request.node.get_closest_marker('get_page')
|
| 60 | 60 |
close_all_but_one_window(_driver) |
| 61 | 61 |
_driver.get(nav_target.args[0] if nav_target else 'about:blank') |
| 62 |
_driver.implicitly_wait(0) |
|
| 62 | 63 |
yield _driver |
| 63 | 64 |
|
| 64 | 65 |
@pytest.fixture() |
| test/unit/test_popup.py | ||
|---|---|---|
| 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 |
import json |
|
| 22 |
from selenium.webdriver.support.ui import WebDriverWait |
|
| 23 |
|
|
| 24 |
from ..extension_crafting import ExtraHTML |
|
| 25 |
from ..script_loader import load_script |
|
| 26 |
from .utils import * |
|
| 27 |
|
|
| 28 |
def reload_with_target(driver, target): |
|
| 29 |
current_url = driver.execute_script('return location.href')
|
|
| 30 |
driver.execute_script( |
|
| 31 |
''' |
|
| 32 |
window.location.href = arguments[0]; |
|
| 33 |
window.location.reload(); |
|
| 34 |
''', |
|
| 35 |
f'{current_url}#{target}')
|
|
| 36 |
|
|
| 37 |
unprivileged_page_info = {
|
|
| 38 |
'url': 'https://example_a.com/something', |
|
| 39 |
'allow': False |
|
| 40 |
} |
|
| 41 |
|
|
| 42 |
mocked_page_infos = {
|
|
| 43 |
'privileged': {
|
|
| 44 |
'url': 'moz-extension://<some-id>/file.html', |
|
| 45 |
'privileged': True |
|
| 46 |
}, |
|
| 47 |
'blocked_default': unprivileged_page_info, |
|
| 48 |
'allowed_default': {
|
|
| 49 |
**unprivileged_page_info, |
|
| 50 |
'allow': True |
|
| 51 |
}, |
|
| 52 |
'blocked_rule': {
|
|
| 53 |
**unprivileged_page_info, |
|
| 54 |
'mapping': '~allow' |
|
| 55 |
}, |
|
| 56 |
'allowed_rule': {
|
|
| 57 |
**unprivileged_page_info, |
|
| 58 |
'allow': True, |
|
| 59 |
'mapping': '~allow' |
|
| 60 |
}, |
|
| 61 |
'mapping': {
|
|
| 62 |
**unprivileged_page_info, |
|
| 63 |
'mapping': 'm1', |
|
| 64 |
'payload': {'identifier': 'res1'}
|
|
| 65 |
} |
|
| 66 |
} |
|
| 67 |
|
|
| 68 |
tab_mock_js = ''' |
|
| 69 |
; |
|
| 70 |
const mocked_page_info = (%s)[/#mock_page_info-(.*)$/.exec(document.URL)[1]]; |
|
| 71 |
browser.tabs.sendMessage = async function(tab_id, msg) {
|
|
| 72 |
const this_tab_id = (await browser.tabs.getCurrent()).id; |
|
| 73 |
if (tab_id !== this_tab_id) |
|
| 74 |
throw `not current tab id (${tab_id} instead of ${this_tab_id})`;
|
|
| 75 |
|
|
| 76 |
if (msg[0] === "page_info") {
|
|
| 77 |
return mocked_page_info; |
|
| 78 |
} else if (msg[0] === "repo_query") {
|
|
| 79 |
const response = await fetch(msg[1]); |
|
| 80 |
if (!response) |
|
| 81 |
return {error: "Something happened :o"};
|
|
| 82 |
|
|
| 83 |
const result = {ok: response.ok, status: response.status};
|
|
| 84 |
try {
|
|
| 85 |
result.json = await response.json(); |
|
| 86 |
} catch(e) {
|
|
| 87 |
result.error_json = "" + e; |
|
| 88 |
} |
|
| 89 |
return result; |
|
| 90 |
} else {
|
|
| 91 |
throw `bad sendMessage message type: '${msg[0]}'`;
|
|
| 92 |
} |
|
| 93 |
} |
|
| 94 |
|
|
| 95 |
const old_tabs_query = browser.tabs.query; |
|
| 96 |
browser.tabs.query = async function(query) {
|
|
| 97 |
const tabs = await old_tabs_query(query); |
|
| 98 |
tabs.forEach(t => t.url = mocked_page_info.url); |
|
| 99 |
return tabs; |
|
| 100 |
} |
|
| 101 |
''' % json.dumps(mocked_page_infos) |
|
| 102 |
|
|
| 103 |
popup_ext_data = {
|
|
| 104 |
'background_script': broker_js, |
|
| 105 |
'extra_html': ExtraHTML( |
|
| 106 |
'html/popup.html', |
|
| 107 |
{
|
|
| 108 |
'common/browser.js': tab_mock_js, |
|
| 109 |
'common/indexeddb.js': '; set_repo("https://hydril.la/");'
|
|
| 110 |
}, |
|
| 111 |
wrap_into_htmldoc=False |
|
| 112 |
), |
|
| 113 |
'navigate_to': 'html/popup.html' |
|
| 114 |
} |
|
| 115 |
|
|
| 116 |
@pytest.mark.ext_data(popup_ext_data) |
|
| 117 |
@pytest.mark.usefixtures('webextension')
|
|
| 118 |
@pytest.mark.parametrize('page_info_key', ['', *mocked_page_infos.keys()])
|
|
| 119 |
def test_popup_display(driver, execute_in_page, page_info_key): |
|
| 120 |
""" |
|
| 121 |
Test popup viewing while on a page. Test parametrized with different |
|
| 122 |
possible values of page_info object passed in message from the content |
|
| 123 |
script. |
|
| 124 |
""" |
|
| 125 |
reload_with_target(driver, f'mock_page_info-{page_info_key}')
|
|
| 126 |
|
|
| 127 |
by_id = driver.execute_script('''
|
|
| 128 |
const nodes = [...document.querySelectorAll("[id]")];
|
|
| 129 |
return nodes.reduce((ob, node) => Object.assign(ob, {[node.id]: node}), {});
|
|
| 130 |
'''); |
|
| 131 |
|
|
| 132 |
if page_info_key == '': |
|
| 133 |
error_msg = 'Page info not avaialable. Try reloading the page.' |
|
| 134 |
error_msg_shown = lambda d: by_id['loading_info'].text == error_msg |
|
| 135 |
WebDriverWait(driver, 10).until(error_msg_shown) |
|
| 136 |
return |
|
| 137 |
|
|
| 138 |
WebDriverWait(driver, 10).until(lambda d: by_id['info_form'].is_displayed()) |
|
| 139 |
assert (page_info_key == 'privileged') == \ |
|
| 140 |
by_id['privileged_page_info'].is_displayed() |
|
| 141 |
assert (page_info_key == 'privileged') ^ \ |
|
| 142 |
by_id['unprivileged_page_info'].is_displayed() |
|
| 143 |
assert by_id['page_url'].text == mocked_page_infos[page_info_key]['url'] |
|
| 144 |
assert not by_id['repo_query_container'].is_displayed() |
|
| 145 |
|
|
| 146 |
if 'blocked' in page_info_key or page_info_key == 'mapping': |
|
| 147 |
assert by_id['scripts_blocked'].text.lower() == 'yes' |
|
| 148 |
elif 'allowed' in page_info_key: |
|
| 149 |
assert by_id['scripts_blocked'].text.lower() == 'no' |
|
| 150 |
|
|
| 151 |
if page_info_key == 'mapping': |
|
| 152 |
assert by_id['injected_payload'].text == 'res1' |
|
| 153 |
elif page_info_key != 'privileged': |
|
| 154 |
assert by_id['injected_payload'].text == 'None' |
|
| 155 |
|
|
| 156 |
mapping_text = by_id['mapping_used'].text |
|
| 157 |
if page_info_key == 'mapping': |
|
| 158 |
assert mapping_text == 'm1' |
|
| 159 |
|
|
| 160 |
if 'allowed' in page_info_key: |
|
| 161 |
'None (scripts allowed by' in mapping_text |
|
| 162 |
elif 'blocked' in page_info_key: |
|
| 163 |
'None (scripts blocked by' in mapping_text |
|
| 164 |
|
|
| 165 |
if 'rule' in page_info_key: |
|
| 166 |
'by a rule)' in mapping_text |
|
| 167 |
elif 'default' in page_info_key: |
|
| 168 |
'by default_policy)' in mapping_text |
|
| 169 |
|
|
| 170 |
@pytest.mark.ext_data(popup_ext_data) |
|
| 171 |
@pytest.mark.usefixtures('webextension')
|
|
| 172 |
def test_popup_repo_query(driver, execute_in_page): |
|
| 173 |
""" |
|
| 174 |
Test opening and closing the repo query view in popup. |
|
| 175 |
""" |
|
| 176 |
reload_with_target(driver, f'mock_page_info-blocked_rule') |
|
| 177 |
|
|
| 178 |
search_but = driver.find_element_by_id("search_resources_but")
|
|
| 179 |
WebDriverWait(driver, 10).until(lambda d: search_but.is_displayed()) |
|
| 180 |
search_but.click() |
|
| 181 |
containers = dict([(name, driver.find_element_by_id(f'{name}_container'))
|
|
| 182 |
for name in ('page_info', 'repo_query')])
|
|
| 183 |
assert not containers['page_info'].is_displayed() |
|
| 184 |
assert containers['repo_query'].is_displayed() |
|
| 185 |
shown = lambda d: 'https://hydril.la/' in containers['repo_query'].text |
|
| 186 |
WebDriverWait(driver, 10).until(shown) |
|
| 187 |
|
|
| 188 |
# Click the "Show results" button. |
|
| 189 |
selector = '.repo_query_buttons > button:first-child' |
|
| 190 |
driver.find_element_by_css_selector(selector).click() |
|
| 191 |
shown = lambda d: 'MAPPING_A' in containers['repo_query'].text |
|
| 192 |
WebDriverWait(driver, 10).until(shown) |
|
| 193 |
|
|
| 194 |
# Click the "Cancel" button |
|
| 195 |
selector = '.repo_query_bottom_buttons > button' |
|
| 196 |
driver.find_element_by_css_selector(selector).click() |
|
| 197 |
assert containers['page_info'].is_displayed() |
|
| 198 |
assert not containers['repo_query'].is_displayed() |
|
| 199 |
|
|
| 200 |
@pytest.mark.ext_data(popup_ext_data) |
|
| 201 |
@pytest.mark.usefixtures('webextension')
|
|
| 202 |
def test_popup_settings_opening(driver, execute_in_page): |
|
| 203 |
""" |
|
| 204 |
Test opening the settings page from popup through button click. |
|
| 205 |
""" |
|
| 206 |
driver.find_element_by_id("settings_but").click()
|
|
| 207 |
|
|
| 208 |
first_handle = driver.current_window_handle |
|
| 209 |
WebDriverWait(driver, 10).until(lambda d: len(d.window_handles) == 2) |
|
| 210 |
new_handle = [h for h in driver.window_handles if h != first_handle][0] |
|
| 211 |
|
|
| 212 |
driver.switch_to.window(new_handle) |
|
| 213 |
driver.implicitly_wait(10) |
|
| 214 |
assert "Extension's options page for testing" in \ |
|
| 215 |
driver.find_element_by_tag_name("h1").text
|
|
| test/unit/test_repo_query.py | ||
|---|---|---|
| 1 | 1 |
# SPDX-License-Identifier: CC0-1.0 |
| 2 | 2 |
|
| 3 | 3 |
""" |
| 4 |
Haketilo unit tests - .............
|
|
| 4 |
Haketilo unit tests - repository querying
|
|
| 5 | 5 |
""" |
| 6 | 6 |
|
| 7 | 7 |
# This file is part of Haketilo |
| ... | ... | |
| 18 | 18 |
# CC0 1.0 Universal License for more details. |
| 19 | 19 |
|
| 20 | 20 |
import pytest |
| 21 |
import json |
|
| 22 | 21 |
from selenium.webdriver.support.ui import WebDriverWait |
| 23 | 22 |
|
| 24 |
from ..extension_crafting import ExtraHTML |
|
| 25 |
from ..script_loader import load_script |
|
| 26 |
|
|
| 27 | 23 |
from ..extension_crafting import ExtraHTML |
| 28 | 24 |
from ..script_loader import load_script |
| 29 | 25 |
from .utils import * |
| ... | ... | |
| 172 | 168 |
show_and_wait_for_repo_entry() |
| 173 | 169 |
|
| 174 | 170 |
elem = execute_in_page('returnval(view.url_span.parentNode);')
|
| 175 |
assert has_msg(f'Browsing custom resources for {queried_url}.', elem)(0)
|
|
| 171 |
assert has_msg(f'Browsing custom resources for: {queried_url}', elem)(0)
|
|
| 176 | 172 |
elif message == 'no_repos': |
| 177 | 173 |
setup_view(execute_in_page, []) |
| 178 | 174 |
show_and_wait_for_repo_entry() |
| ... | ... | |
| 272 | 268 |
''') |
| 273 | 269 |
show_and_wait_for_repo_entry() |
| 274 | 270 |
|
| 275 |
elem = execute_in_page('returnval(view.repo_entries[0].results_list);')
|
|
| 271 |
elem = execute_in_page('returnval(view.repo_entries[0].info_span);')
|
|
| 276 | 272 |
WebDriverWait(driver, 10).until(has_msg('No results :(', elem))
|
| 277 | 273 |
else: |
| 278 | 274 |
raise Exception('made a typo in test function params?')
|
Also available in: Unified diff
add new extension's popup page