Update upstream source from tag 'upstream/3.6'
Update to upstream version '3.6'
with Debian dir 038f6170e38189e678732b6ccfc7c945ba6c956c
Carsten Schoenert
1 year, 8 months ago
29 | 29 | - 3306:3306 |
30 | 30 | |
31 | 31 | steps: |
32 | - uses: actions/checkout@v2 | |
33 | ||
34 | - name: Set up Python ${{ matrix.python-version }} | |
35 | uses: actions/setup-python@v2 | |
32 | - uses: actions/checkout@v3 | |
33 | ||
34 | - name: Set up Python ${{ matrix.python-version }} | |
35 | uses: actions/setup-python@v4 | |
36 | 36 | with: |
37 | 37 | python-version: ${{ matrix.python-version }} |
38 | 38 | |
42 | 42 | echo "::set-output name=dir::$(pip cache dir)" |
43 | 43 | |
44 | 44 | - name: Cache |
45 | uses: actions/cache@v2 | |
45 | uses: actions/cache@v3 | |
46 | 46 | with: |
47 | 47 | path: ${{ steps.pip-cache.outputs.dir }} |
48 | 48 | key: |
70 | 70 | DB_PORT: 3306 |
71 | 71 | |
72 | 72 | - name: Upload coverage data |
73 | uses: actions/upload-artifact@v2 | |
73 | uses: actions/upload-artifact@v3 | |
74 | 74 | with: |
75 | 75 | name: coverage-data |
76 | 76 | path: ".coverage.*" |
100 | 100 | --health-retries 5 |
101 | 101 | |
102 | 102 | steps: |
103 | - uses: actions/checkout@v2 | |
104 | ||
105 | - name: Set up Python ${{ matrix.python-version }} | |
106 | uses: actions/setup-python@v2 | |
103 | - uses: actions/checkout@v3 | |
104 | ||
105 | - name: Set up Python ${{ matrix.python-version }} | |
106 | uses: actions/setup-python@v4 | |
107 | 107 | with: |
108 | 108 | python-version: ${{ matrix.python-version }} |
109 | 109 | |
113 | 113 | echo "::set-output name=dir::$(pip cache dir)" |
114 | 114 | |
115 | 115 | - name: Cache |
116 | uses: actions/cache@v2 | |
116 | uses: actions/cache@v3 | |
117 | 117 | with: |
118 | 118 | path: ${{ steps.pip-cache.outputs.dir }} |
119 | 119 | key: |
139 | 139 | DB_PORT: 5432 |
140 | 140 | |
141 | 141 | - name: Upload coverage data |
142 | uses: actions/upload-artifact@v2 | |
142 | uses: actions/upload-artifact@v3 | |
143 | 143 | with: |
144 | 144 | name: coverage-data |
145 | 145 | path: ".coverage.*" |
153 | 153 | python-version: ['3.7', '3.8', '3.9', '3.10'] |
154 | 154 | |
155 | 155 | steps: |
156 | - uses: actions/checkout@v2 | |
157 | ||
158 | - name: Set up Python ${{ matrix.python-version }} | |
159 | uses: actions/setup-python@v2 | |
156 | - uses: actions/checkout@v3 | |
157 | ||
158 | - name: Set up Python ${{ matrix.python-version }} | |
159 | uses: actions/setup-python@v4 | |
160 | 160 | with: |
161 | 161 | python-version: ${{ matrix.python-version }} |
162 | 162 | |
166 | 166 | echo "::set-output name=dir::$(pip cache dir)" |
167 | 167 | |
168 | 168 | - name: Cache |
169 | uses: actions/cache@v2 | |
169 | uses: actions/cache@v3 | |
170 | 170 | with: |
171 | 171 | path: ${{ steps.pip-cache.outputs.dir }} |
172 | 172 | key: |
186 | 186 | DB_NAME: ":memory:" |
187 | 187 | |
188 | 188 | - name: Upload coverage data |
189 | uses: actions/upload-artifact@v2 | |
189 | uses: actions/upload-artifact@v3 | |
190 | 190 | with: |
191 | 191 | name: coverage-data |
192 | 192 | path: ".coverage.*" |
196 | 196 | runs-on: "ubuntu-latest" |
197 | 197 | needs: [sqlite, mysql, postgres] |
198 | 198 | steps: |
199 | - uses: actions/checkout@v2 | |
200 | - uses: actions/setup-python@v2 | |
199 | - uses: actions/checkout@v3 | |
200 | - uses: actions/setup-python@v4 | |
201 | 201 | with: |
202 | 202 | # Use latest, so it understands all syntax. |
203 | 203 | python-version: "3.10" |
205 | 205 | - run: python -m pip install --upgrade coverage |
206 | 206 | |
207 | 207 | - name: Download coverage data. |
208 | uses: actions/download-artifact@v2 | |
208 | uses: actions/download-artifact@v3 | |
209 | 209 | with: |
210 | 210 | name: coverage-data |
211 | 211 | |
216 | 216 | python -m coverage report |
217 | 217 | |
218 | 218 | - name: Upload HTML report if check failed. |
219 | uses: actions/upload-artifact@v2 | |
219 | uses: actions/upload-artifact@v3 | |
220 | 220 | with: |
221 | 221 | name: html-report |
222 | 222 | path: htmlcov |
228 | 228 | fail-fast: false |
229 | 229 | |
230 | 230 | steps: |
231 | - uses: actions/checkout@v2 | |
232 | ||
233 | - name: Set up Python ${{ matrix.python-version }} | |
234 | uses: actions/setup-python@v2 | |
231 | - uses: actions/checkout@v3 | |
232 | ||
233 | - name: Set up Python ${{ matrix.python-version }} | |
234 | uses: actions/setup-python@v4 | |
235 | 235 | with: |
236 | 236 | python-version: 3.8 |
237 | 237 | |
241 | 241 | echo "::set-output name=dir::$(pip cache dir)" |
242 | 242 | |
243 | 243 | - name: Cache |
244 | uses: actions/cache@v2 | |
244 | uses: actions/cache@v3 | |
245 | 245 | with: |
246 | 246 | path: ${{ steps.pip-cache.outputs.dir }} |
247 | 247 | key: |
6 | 6 | - id: trailing-whitespace |
7 | 7 | - id: mixed-line-ending |
8 | 8 | - repo: https://github.com/pycqa/flake8 |
9 | rev: 4.0.1 | |
9 | rev: 5.0.4 | |
10 | 10 | hooks: |
11 | 11 | - id: flake8 |
12 | 12 | - repo: https://github.com/pycqa/doc8 |
13 | rev: 0.11.2 | |
13 | rev: v1.0.0 | |
14 | 14 | hooks: |
15 | 15 | - id: doc8 |
16 | 16 | - repo: https://github.com/asottile/pyupgrade |
17 | rev: v2.34.0 | |
17 | rev: v2.37.3 | |
18 | 18 | hooks: |
19 | 19 | - id: pyupgrade |
20 | 20 | args: [--py37-plus] |
21 | 21 | - repo: https://github.com/adamchainz/django-upgrade |
22 | rev: 1.7.0 | |
22 | rev: 1.8.0 | |
23 | 23 | hooks: |
24 | 24 | - id: django-upgrade |
25 | 25 | args: [--target-version, "3.2"] |
42 | 42 | - id: prettier |
43 | 43 | types_or: [javascript, css] |
44 | 44 | - repo: https://github.com/pre-commit/mirrors-eslint |
45 | rev: v8.18.0 | |
45 | rev: v8.22.0 | |
46 | 46 | hooks: |
47 | 47 | - id: eslint |
48 | 48 | files: \.js?$ |
50 | 50 | args: |
51 | 51 | - --fix |
52 | 52 | - repo: https://github.com/psf/black |
53 | rev: 22.3.0 | |
53 | rev: 22.6.0 | |
54 | 54 | hooks: |
55 | 55 | - id: black |
56 | 56 | language_version: python3 |
43 | 43 | In addition to the built-in panels, a number of third-party panels are |
44 | 44 | contributed by the community. |
45 | 45 | |
46 | The current stable version of the Debug Toolbar is 3.5.0. It works on | |
47 | Django ≥ 3.2. | |
46 | The current stable version of the Debug Toolbar is 3.6.0. It works on | |
47 | Django ≥ 3.2.4. | |
48 | 48 | |
49 | 49 | Documentation, including installation and configuration instructions, is |
50 | 50 | available at https://django-debug-toolbar.readthedocs.io/. |
3 | 3 | |
4 | 4 | # Do not use pkg_resources to find the version but set it here directly! |
5 | 5 | # see issue #1446 |
6 | VERSION = "3.5.0" | |
6 | VERSION = "3.6.0" | |
7 | 7 | |
8 | 8 | # Code that discovers files or modules in INSTALLED_APPS imports this module. |
9 | 9 | urls = "debug_toolbar.urls", APP_NAME |
0 | 0 | import functools |
1 | 1 | |
2 | from django.http import Http404, HttpResponseBadRequest | |
2 | from django.http import Http404 | |
3 | 3 | |
4 | 4 | |
5 | 5 | def require_show_toolbar(view): |
14 | 14 | return view(request, *args, **kwargs) |
15 | 15 | |
16 | 16 | return inner |
17 | ||
18 | ||
19 | def signed_data_view(view): | |
20 | """Decorator that handles unpacking a signed data form""" | |
21 | ||
22 | @functools.wraps(view) | |
23 | def inner(request, *args, **kwargs): | |
24 | from debug_toolbar.forms import SignedDataForm | |
25 | ||
26 | data = request.GET if request.method == "GET" else request.POST | |
27 | signed_form = SignedDataForm(data) | |
28 | if signed_form.is_valid(): | |
29 | return view( | |
30 | request, *args, verified_data=signed_form.verified_data(), **kwargs | |
31 | ) | |
32 | return HttpResponseBadRequest("Invalid signature") | |
33 | ||
34 | return inner |
20 | 20 | panel_form = PanelForm(signed_form.verified_data) |
21 | 21 | if panel_form.is_valid(): |
22 | 22 | # Success |
23 | Or wrap the FBV with ``debug_toolbar.decorators.signed_data_view`` | |
24 | 23 | """ |
25 | 24 | |
26 | 25 | salt = "django_debug_toolbar" |
23 | 23 | observe_request = self.toolbar.get_observe_request() |
24 | 24 | store_id = getattr(self.toolbar, "store_id") |
25 | 25 | if store_id and observe_request(request): |
26 | headers["DJDT-STORE-ID"] = store_id | |
26 | headers["djdt-store-id"] = store_id | |
27 | 27 | return headers |
28 | 28 | |
29 | 29 | @property |
68 | 68 | |
69 | 69 | def contrasting_color_generator(): |
70 | 70 | """ |
71 | Generate constrasting colors by varying most significant bit of RGB first, | |
71 | Generate contrasting colors by varying most significant bit of RGB first, | |
72 | 72 | and then vary subsequent bits systematically. |
73 | 73 | """ |
74 | 74 |
1 | 1 | from django.template.loader import render_to_string |
2 | 2 | from django.views.decorators.csrf import csrf_exempt |
3 | 3 | |
4 | from debug_toolbar.decorators import require_show_toolbar, signed_data_view | |
4 | from debug_toolbar.decorators import require_show_toolbar | |
5 | from debug_toolbar.forms import SignedDataForm | |
5 | 6 | from debug_toolbar.panels.sql.forms import SQLSelectForm |
7 | ||
8 | ||
9 | def get_signed_data(request): | |
10 | """Unpack a signed data form, if invalid returns None""" | |
11 | data = request.GET if request.method == "GET" else request.POST | |
12 | signed_form = SignedDataForm(data) | |
13 | if signed_form.is_valid(): | |
14 | return signed_form.verified_data() | |
15 | return None | |
6 | 16 | |
7 | 17 | |
8 | 18 | @csrf_exempt |
9 | 19 | @require_show_toolbar |
10 | @signed_data_view | |
11 | def sql_select(request, verified_data): | |
20 | def sql_select(request): | |
12 | 21 | """Returns the output of the SQL SELECT statement""" |
22 | verified_data = get_signed_data(request) | |
23 | if not verified_data: | |
24 | return HttpResponseBadRequest("Invalid signature") | |
13 | 25 | form = SQLSelectForm(verified_data) |
14 | 26 | |
15 | 27 | if form.is_valid(): |
34 | 46 | |
35 | 47 | @csrf_exempt |
36 | 48 | @require_show_toolbar |
37 | @signed_data_view | |
38 | def sql_explain(request, verified_data): | |
49 | def sql_explain(request): | |
39 | 50 | """Returns the output of the SQL EXPLAIN on the given query""" |
51 | verified_data = get_signed_data(request) | |
52 | if not verified_data: | |
53 | return HttpResponseBadRequest("Invalid signature") | |
40 | 54 | form = SQLSelectForm(verified_data) |
41 | 55 | |
42 | 56 | if form.is_valid(): |
70 | 84 | |
71 | 85 | @csrf_exempt |
72 | 86 | @require_show_toolbar |
73 | @signed_data_view | |
74 | def sql_profile(request, verified_data): | |
87 | def sql_profile(request): | |
75 | 88 | """Returns the output of running the SQL and getting the profiling statistics""" |
89 | verified_data = get_signed_data(request) | |
90 | if not verified_data: | |
91 | return HttpResponseBadRequest("Invalid signature") | |
76 | 92 | form = SQLSelectForm(verified_data) |
77 | 93 | |
78 | 94 | if form.is_valid(): |
2 | 2 | from django.template import Origin, TemplateDoesNotExist |
3 | 3 | from django.template.engine import Engine |
4 | 4 | from django.template.loader import render_to_string |
5 | from django.utils.safestring import mark_safe | |
5 | from django.utils.html import format_html, mark_safe | |
6 | 6 | |
7 | 7 | from debug_toolbar.decorators import require_show_toolbar |
8 | 8 | |
49 | 49 | from pygments import highlight |
50 | 50 | from pygments.formatters import HtmlFormatter |
51 | 51 | from pygments.lexers import HtmlDjangoLexer |
52 | ||
52 | except ModuleNotFoundError: | |
53 | source = format_html("<code>{}</code>", source) | |
54 | else: | |
53 | 55 | source = highlight(source, HtmlDjangoLexer(), HtmlFormatter()) |
54 | 56 | source = mark_safe(source) |
55 | source.pygmentized = True | |
56 | except ImportError: | |
57 | pass | |
58 | 57 | |
59 | 58 | content = render_to_string( |
60 | 59 | "debug_toolbar/panels/template_source.html", |
263 | 263 | const origOpen = XMLHttpRequest.prototype.open; |
264 | 264 | XMLHttpRequest.prototype.open = function () { |
265 | 265 | this.addEventListener("load", function () { |
266 | let store_id = this.getResponseHeader("djdt-store-id"); | |
267 | if (store_id !== null) { | |
266 | // Chromium emits a "Refused to get unsafe header" uncatchable warning | |
267 | // when the header can't be fetched. While it doesn't impede execution | |
268 | // it's worrisome to developers. | |
269 | if ( | |
270 | this.getAllResponseHeaders().indexOf("djdt-store-id") >= 0 | |
271 | ) { | |
272 | let store_id = this.getResponseHeader("djdt-store-id"); | |
268 | 273 | store_id = encodeURIComponent(store_id); |
269 | 274 | const dest = `${sidebar_url}?store_id=${store_id}`; |
270 | 275 | slowjax(dest).then(function (data) { |
4 | 4 | </div> |
5 | 5 | <div class="djDebugPanelContent"> |
6 | 6 | <div class="djdt-scroll"> |
7 | {% if not source.pygmentized %} | |
8 | <code>{{ source }}</code> | |
9 | {% else %} | |
10 | {{ source }} | |
11 | {% endif %} | |
7 | {{ source }} | |
12 | 8 | </div> |
13 | 9 | </div> |
0 | 0 | Change log |
1 | 1 | ========== |
2 | ||
3 | Pending | |
4 | ------- | |
5 | ||
6 | 3.6.0 (2022-08-17) | |
7 | ------------------ | |
8 | ||
9 | * Remove decorator ``signed_data_view`` as it was causing issues with | |
10 | `django-urlconfchecks <https://github.com/AliSayyah/django-urlconfchecks/>`__. | |
11 | * Added pygments to the test environment and fixed a crash when using the | |
12 | template panel with Django 4.1 and pygments installed. | |
13 | * Stayed on top of pre-commit hook and GitHub actions updates. | |
14 | * Added some workarounds to avoid a Chromium warning which was worrisome to | |
15 | developers. | |
16 | * Avoided using deprecated Selenium methods to find elements. | |
17 | * Raised the minimum Django version from 3.2 to 3.2.4 so that we can take | |
18 | advantage of backported improvements to the cache connection handler. | |
2 | 19 | |
3 | 20 | 3.5.0 (2022-06-23) |
4 | 21 | ------------------ |
24 | 24 | copyright = copyright.format(datetime.date.today().year) |
25 | 25 | |
26 | 26 | # The full version, including alpha/beta/rc tags |
27 | release = "3.5.0" | |
27 | release = "3.6.0" | |
28 | 28 | |
29 | 29 | |
30 | 30 | # -- General configuration --------------------------------------------------- |
141 | 141 | |
142 | 142 | * ``OBSERVE_REQUEST_CALLBACK`` |
143 | 143 | |
144 | Default: ``'debug_toolbar.middleware.observe_request'`` | |
144 | Default: ``'debug_toolbar.toolbar.observe_request'`` | |
145 | 145 | |
146 | 146 | This is the dotted path to a function used for determining whether the |
147 | 147 | toolbar should update on AJAX requests or not. The default checks are that |
137 | 137 | If using Docker the following will set your ``INTERNAL_IPS`` correctly in Debug mode:: |
138 | 138 | |
139 | 139 | if DEBUG: |
140 | import os # only if you haven't already imported this | |
141 | 140 | import socket # only if you haven't already imported this |
142 | 141 | hostname, _, ips = socket.gethostbyname_ex(socket.gethostname()) |
143 | 142 | INTERNAL_IPS = [ip[: ip.rfind(".")] + ".1" for ip in ips] + ["127.0.0.1", "10.0.2.2"] |
0 | 0 | backend |
1 | 1 | backends |
2 | backported | |
2 | 3 | checkbox |
3 | 4 | contrib |
4 | 5 | django |
29 | 30 | Pympler |
30 | 31 | querysets |
31 | 32 | refactoring |
33 | resizing | |
34 | spellchecking | |
32 | 35 | spooler |
33 | 36 | stacktrace |
34 | 37 | stacktraces |
38 | startup | |
35 | 39 | timeline |
36 | 40 | tox |
37 | 41 | Transifex |
4 | 4 | import subprocess |
5 | 5 | from time import sleep |
6 | 6 | |
7 | from selenium.webdriver.common.by import By | |
7 | 8 | from selenium.webdriver.common.keys import Keys |
8 | 9 | from selenium.webdriver.support import expected_conditions as EC |
9 | 10 | from selenium.webdriver.support.wait import WebDriverWait |
53 | 54 | def submit_form(selenium, data): |
54 | 55 | url = selenium.current_url |
55 | 56 | for name, value in data.items(): |
56 | el = selenium.find_element_by_name(name) | |
57 | el = selenium.find_element(By.NAME, name) | |
57 | 58 | el.send_keys(value) |
58 | 59 | el.send_keys(Keys.RETURN) |
59 | 60 | WebDriverWait(selenium, timeout=5).until(EC.url_changes(url)) |
71 | 72 | |
72 | 73 | selenium.get("http://localhost:8000/admin/auth/user/") |
73 | 74 | # Check if SQL Panel is already visible: |
74 | sql_panel = selenium.find_element_by_id("djdt-SQLPanel") | |
75 | sql_panel = selenium.find_element(By.ID, "djdt-SQLPanel") | |
75 | 76 | if not sql_panel: |
76 | 77 | # Open the admin sidebar. |
77 | el = selenium.find_element_by_id("djDebugToolbarHandle") | |
78 | el = selenium.find_element(By.ID, "djDebugToolbarHandle") | |
78 | 79 | el.click() |
79 | sql_panel = selenium.find_element_by_id("djdt-SQLPanel") | |
80 | sql_panel = selenium.find_element(By.ID, "djdt-SQLPanel") | |
80 | 81 | # Open the SQL panel. |
81 | 82 | sql_panel.click() |
82 | 83 |
0 | 0 | [metadata] |
1 | 1 | name = django-debug-toolbar |
2 | version = 3.5.0 | |
2 | version = 3.6.0 | |
3 | 3 | description = A configurable set of panels that display various debug information about the current request/response. |
4 | 4 | long_description = file: README.rst |
5 | 5 | long_description_content_type = text/x-rst |
15 | 15 | Framework :: Django |
16 | 16 | Framework :: Django :: 3.2 |
17 | 17 | Framework :: Django :: 4.0 |
18 | Framework :: Django :: 4.1 | |
18 | 19 | Intended Audience :: Developers |
19 | 20 | License :: OSI Approved :: BSD License |
20 | 21 | Operating System :: OS Independent |
30 | 31 | [options] |
31 | 32 | python_requires = >=3.7 |
32 | 33 | install_requires = |
33 | Django >= 3.2 | |
34 | Django >= 3.2.4 | |
34 | 35 | sqlparse >= 0.2.0 |
35 | 36 | packages = find: |
36 | 37 | include_package_data = true |
98 | 98 | response = self.client.get(reverse("djdt:history_sidebar")) |
99 | 99 | self.assertEqual(response.status_code, 400) |
100 | 100 | |
101 | def test_history_headers(self): | |
102 | """Validate the headers injected from the history panel.""" | |
103 | response = self.client.get("/json_view/") | |
104 | store_id = list(DebugToolbar._store)[0] | |
105 | self.assertEqual(response.headers["djdt-store-id"], store_id) | |
106 | ||
107 | @override_settings( | |
108 | DEBUG_TOOLBAR_CONFIG={"OBSERVE_REQUEST_CALLBACK": lambda request: False} | |
109 | ) | |
110 | def test_history_headers_unobserved(self): | |
111 | """Validate the headers aren't injected from the history panel.""" | |
112 | response = self.client.get("/json_view/") | |
113 | self.assertNotIn("djdt-store-id", response.headers) | |
114 | ||
101 | 115 | def test_history_sidebar(self): |
102 | 116 | """Validate the history sidebar view.""" |
103 | 117 | self.client.get("/json_view/") |
443 | 443 | |
444 | 444 | # Reset the queries |
445 | 445 | self.panel._queries = [] |
446 | # Run it again, but with prettyify off. Verify that it's different. | |
446 | # Run it again, but with prettify off. Verify that it's different. | |
447 | 447 | dt_settings.get_config()["PRETTIFY_SQL"] = False |
448 | 448 | list(User.objects.filter(username__istartswith="spam")) |
449 | 449 | response = self.panel.process_request(self.request) |
452 | 452 | self.assertNotEqual(pretty_sql, self.panel._queries[-1]["sql"]) |
453 | 453 | |
454 | 454 | self.panel._queries = [] |
455 | # Run it again, but with prettyify back on. | |
455 | # Run it again, but with prettify back on. | |
456 | 456 | # This is so we don't have to check what PRETTIFY_SQL does exactly, |
457 | 457 | # but we know it's doing something. |
458 | 458 | dt_settings.get_config()["PRETTIFY_SQL"] = True |
481 | 481 | |
482 | 482 | def test_basic(self): |
483 | 483 | self.get("/regular/basic/") |
484 | version_panel = self.selenium.find_element_by_id("VersionsPanel") | |
484 | version_panel = self.selenium.find_element(By.ID, "VersionsPanel") | |
485 | 485 | |
486 | 486 | # Versions panel isn't loaded |
487 | 487 | with self.assertRaises(NoSuchElementException): |
488 | version_panel.find_element_by_tag_name("table") | |
488 | version_panel.find_element(By.TAG_NAME, "table") | |
489 | 489 | |
490 | 490 | # Click to show the versions panel |
491 | self.selenium.find_element_by_class_name("VersionsPanel").click() | |
491 | self.selenium.find_element(By.CLASS_NAME, "VersionsPanel").click() | |
492 | 492 | |
493 | 493 | # Version panel loads |
494 | 494 | table = self.wait.until( |
495 | lambda selenium: version_panel.find_element_by_tag_name("table") | |
495 | lambda selenium: version_panel.find_element(By.TAG_NAME, "table") | |
496 | 496 | ) |
497 | 497 | self.assertIn("Name", table.text) |
498 | 498 | self.assertIn("Version", table.text) |
504 | 504 | ) |
505 | 505 | def test_basic_jinja(self): |
506 | 506 | self.get("/regular_jinja/basic") |
507 | template_panel = self.selenium.find_element_by_id("TemplatesPanel") | |
507 | template_panel = self.selenium.find_element(By.ID, "TemplatesPanel") | |
508 | 508 | |
509 | 509 | # Click to show the template panel |
510 | self.selenium.find_element_by_class_name("TemplatesPanel").click() | |
510 | self.selenium.find_element(By.CLASS_NAME, "TemplatesPanel").click() | |
511 | 511 | |
512 | 512 | self.assertIn("Templates (2 rendered)", template_panel.text) |
513 | 513 | self.assertIn("base.html", template_panel.text) |
522 | 522 | self.get("/regular_jinja/basic") |
523 | 523 | # Make a new request so the history panel has more than one option. |
524 | 524 | self.get("/execute_sql/") |
525 | template_panel = self.selenium.find_element_by_id("HistoryPanel") | |
525 | template_panel = self.selenium.find_element(By.ID, "HistoryPanel") | |
526 | 526 | # Record the current side panel of buttons for later comparison. |
527 | previous_button_panel = self.selenium.find_element_by_id( | |
528 | "djDebugPanelList" | |
527 | previous_button_panel = self.selenium.find_element( | |
528 | By.ID, "djDebugPanelList" | |
529 | 529 | ).text |
530 | 530 | |
531 | 531 | # Click to show the history panel |
532 | self.selenium.find_element_by_class_name("HistoryPanel").click() | |
532 | self.selenium.find_element(By.CLASS_NAME, "HistoryPanel").click() | |
533 | 533 | # Click to switch back to the jinja page view snapshot |
534 | list(template_panel.find_elements_by_css_selector("button"))[-1].click() | |
535 | ||
536 | current_button_panel = self.selenium.find_element_by_id("djDebugPanelList").text | |
534 | list(template_panel.find_elements(By.CSS_SELECTOR, "button"))[-1].click() | |
535 | ||
536 | current_button_panel = self.selenium.find_element( | |
537 | By.ID, "djDebugPanelList" | |
538 | ).text | |
537 | 539 | # Verify the button side panels have updated. |
538 | 540 | self.assertNotEqual(previous_button_panel, current_button_panel) |
539 | 541 | self.assertNotIn("1 query", current_button_panel) |
542 | 544 | @override_settings(DEBUG_TOOLBAR_CONFIG={"RESULTS_CACHE_SIZE": 0}) |
543 | 545 | def test_expired_store(self): |
544 | 546 | self.get("/regular/basic/") |
545 | version_panel = self.selenium.find_element_by_id("VersionsPanel") | |
547 | version_panel = self.selenium.find_element(By.ID, "VersionsPanel") | |
546 | 548 | |
547 | 549 | # Click to show the version panel |
548 | self.selenium.find_element_by_class_name("VersionsPanel").click() | |
550 | self.selenium.find_element(By.CLASS_NAME, "VersionsPanel").click() | |
549 | 551 | |
550 | 552 | # Version panel doesn't loads |
551 | 553 | error = self.wait.until( |
552 | lambda selenium: version_panel.find_element_by_tag_name("p") | |
554 | lambda selenium: version_panel.find_element(By.TAG_NAME, "p") | |
553 | 555 | ) |
554 | 556 | self.assertIn("Data for this panel isn't available anymore.", error.text) |
555 | 557 | |
573 | 575 | ) |
574 | 576 | def test_django_cached_template_loader(self): |
575 | 577 | self.get("/regular/basic/") |
576 | version_panel = self.selenium.find_element_by_id("TemplatesPanel") | |
578 | version_panel = self.selenium.find_element(By.ID, "TemplatesPanel") | |
577 | 579 | |
578 | 580 | # Click to show the templates panel |
579 | self.selenium.find_element_by_class_name("TemplatesPanel").click() | |
581 | self.selenium.find_element(By.CLASS_NAME, "TemplatesPanel").click() | |
580 | 582 | |
581 | 583 | # Templates panel loads |
582 | 584 | trigger = self.wait.until( |
583 | lambda selenium: version_panel.find_element_by_css_selector(".remoteCall") | |
585 | lambda selenium: version_panel.find_element(By.CSS_SELECTOR, ".remoteCall") | |
584 | 586 | ) |
585 | 587 | trigger.click() |
586 | 588 | |
587 | 589 | # Verify the code is displayed |
588 | 590 | self.wait.until( |
589 | lambda selenium: self.selenium.find_element_by_css_selector( | |
590 | "#djDebugWindow code" | |
591 | lambda selenium: self.selenium.find_element( | |
592 | By.CSS_SELECTOR, "#djDebugWindow code" | |
591 | 593 | ) |
592 | 594 | ) |
593 | 595 | |
594 | 596 | def test_sql_action_and_go_back(self): |
595 | 597 | self.get("/execute_sql/") |
596 | sql_panel = self.selenium.find_element_by_id("SQLPanel") | |
597 | debug_window = self.selenium.find_element_by_id("djDebugWindow") | |
598 | sql_panel = self.selenium.find_element(By.ID, "SQLPanel") | |
599 | debug_window = self.selenium.find_element(By.ID, "djDebugWindow") | |
598 | 600 | |
599 | 601 | # Click to show the SQL panel |
600 | self.selenium.find_element_by_class_name("SQLPanel").click() | |
602 | self.selenium.find_element(By.CLASS_NAME, "SQLPanel").click() | |
601 | 603 | |
602 | 604 | # SQL panel loads |
603 | 605 | button = self.wait.until( |
610 | 612 | self.assertIn("SQL selected", debug_window.text) |
611 | 613 | |
612 | 614 | # Close the SQL selected window |
613 | debug_window.find_element_by_class_name("djDebugClose").click() | |
615 | debug_window.find_element(By.CLASS_NAME, "djDebugClose").click() | |
614 | 616 | self.wait.until(EC.invisibility_of_element(debug_window)) |
615 | 617 | |
616 | 618 | # SQL panel is still visible |
619 | 621 | @override_settings(DEBUG_TOOLBAR_PANELS=["tests.test_integration.BuggyPanel"]) |
620 | 622 | def test_displays_server_error(self): |
621 | 623 | self.get("/regular/basic/") |
622 | debug_window = self.selenium.find_element_by_id("djDebugWindow") | |
623 | self.selenium.find_element_by_class_name("BuggyPanel").click() | |
624 | debug_window = self.selenium.find_element(By.ID, "djDebugWindow") | |
625 | self.selenium.find_element(By.CLASS_NAME, "BuggyPanel").click() | |
624 | 626 | self.wait.until(EC.visibility_of(debug_window)) |
625 | 627 | self.assertEqual(debug_window.text, "»\n500: Internal Server Error") |
8 | 8 | deps = |
9 | 9 | dj32: django~=3.2.9 |
10 | 10 | dj40: django~=4.0.0 |
11 | dj41: django>=4.1b1,<4.2 | |
11 | dj41: django~=4.1.0 | |
12 | 12 | postgresql: psycopg2-binary |
13 | 13 | postgis: psycopg2-binary |
14 | 14 | mysql: mysqlclient |
16 | 16 | coverage |
17 | 17 | Jinja2 |
18 | 18 | html5lib |
19 | pygments | |
19 | 20 | selenium |
20 | 21 | sqlparse |
21 | 22 | passenv= |
32 | 33 | PYTHONPATH = {toxinidir} |
33 | 34 | PYTHONWARNINGS = d |
34 | 35 | py39-dj32-postgresql: DJANGO_SELENIUM_TESTS = true |
36 | py310-dj40-postgresql: DJANGO_SELENIUM_TESTS = true | |
35 | 37 | DB_NAME = {env:DB_NAME:debug_toolbar} |
36 | 38 | DB_USER = {env:DB_USER:debug_toolbar} |
37 | 39 | DB_HOST = {env:DB_HOST:localhost} |