that contains calendar
- calendarLinkName: "calendarlink", // name of the link that is used to toggle
+ calendarButtonName: "calendarbutton", // name of the button that is used to toggle
clockDivName: "clockbox", // name of clock
that gets toggled
- clockLinkName: "clocklink", // name of the link that is used to toggle
+ clockButtonName: "clockbutton", // name of the button that is used to toggle
shortCutsClass: "datetimeshortcuts", // class of the clock and cal shortcuts
timezoneWarningClass: "timezonewarning", // class of the warning for timezone mismatch
timezoneOffset: 0,
@@ -128,28 +128,28 @@
const shortcuts_span = document.createElement("span");
shortcuts_span.className = DateTimeShortcuts.shortCutsClass;
inp.parentNode.insertBefore(shortcuts_span, inp.nextSibling);
- const now_link = document.createElement("a");
- now_link.href = "#";
- now_link.textContent = gettext("Now");
- now_link.role = "button";
- now_link.addEventListener("click", function (e) {
+ const now_button = document.createElement("button");
+ now_button.textContent = gettext("Now");
+ now_button.type = "button";
+ now_button.addEventListener("click", function (e) {
e.preventDefault();
DateTimeShortcuts.handleClockQuicklink(num, -1);
});
- const clock_link = document.createElement("button");
- clock_link.type = "button";
- clock_link.id = DateTimeShortcuts.clockLinkName + num;
- clock_link.addEventListener("click", function (e) {
+ const clock_button = document.createElement("button");
+ clock_button.type = "button";
+ clock_button.id = DateTimeShortcuts.clockButtonName + num;
+ clock_button.addEventListener("click", function (e) {
e.preventDefault();
// avoid triggering the document click handler to dismiss the clock
e.stopPropagation();
DateTimeShortcuts.openClock(num);
});
- const clockIconId = DateTimeShortcuts.clockLinkName + num + "_icon";
+ const clockIconId =
+ DateTimeShortcuts.clockButtonName + num + "_icon";
quickElement(
"span",
- clock_link,
+ clock_button,
"",
"id",
clockIconId,
@@ -158,13 +158,13 @@
"title",
gettext("Choose a Time"),
);
- clock_link.setAttribute("aria-labelledby", clockIconId);
+ clock_button.setAttribute("aria-labelledby", clockIconId);
shortcuts_span.appendChild(document.createTextNode("\u00A0"));
- shortcuts_span.appendChild(now_link);
+ shortcuts_span.appendChild(now_button);
shortcuts_span.appendChild(
document.createTextNode("\u00A0|\u00A0"),
);
- shortcuts_span.appendChild(clock_link);
+ shortcuts_span.appendChild(clock_button);
// Create clock link div
//
@@ -173,14 +173,14 @@
// aria-label="Choose a time">
//
Choose a time
//
//
- // Cancel
+ // Cancel
//
//
@@ -205,16 +205,14 @@
? "default_"
: inp.name;
DateTimeShortcuts.clockHours[name].forEach(function (element) {
- const time_link = quickElement(
- "a",
+ const time_button = quickElement(
+ "button",
quickElement("li", time_list),
gettext(element[0]),
- "role",
+ "type",
"button",
- "href",
- "#",
);
- time_link.addEventListener("click", function (e) {
+ time_button.addEventListener("click", function (e) {
e.preventDefault();
DateTimeShortcuts.handleClockQuicklink(num, element[1]);
});
@@ -222,16 +220,14 @@
const cancel_p = quickElement("p", clock_box);
cancel_p.className = "calendar-cancel";
- const cancel_link = quickElement(
- "a",
+ const cancel_button = quickElement(
+ "button",
cancel_p,
gettext("Cancel"),
- "role",
+ "type",
"button",
- "href",
- "#",
);
- cancel_link.addEventListener("click", function (e) {
+ cancel_button.addEventListener("click", function (e) {
e.preventDefault();
DateTimeShortcuts.dismissClock(num);
});
@@ -248,20 +244,21 @@
const clock_box = document.getElementById(
DateTimeShortcuts.clockDivName + num,
);
- const clock_link = document.getElementById(
- DateTimeShortcuts.clockLinkName + num,
+ const clock_button = document.getElementById(
+ DateTimeShortcuts.clockButtonName + num,
);
// Recalculate the clockbox position
// is it left-to-right or right-to-left layout ?
if (window.getComputedStyle(document.body).direction !== "rtl") {
- clock_box.style.left = findPosX(clock_link) + 17 + "px";
+ clock_box.style.left = findPosX(clock_button) + 17 + "px";
} else {
// since style's width is in em, it'd be tough to calculate
// px value of it. let's use an estimated px for now
- clock_box.style.right = findPosX(clock_link) - 110 + "px";
+ clock_box.style.right = findPosX(clock_button) - 110 + "px";
}
- clock_box.style.top = Math.max(0, findPosY(clock_link) - 30) + "px";
+ clock_box.style.top =
+ Math.max(0, findPosY(clock_button) - 30) + "px";
// Show the clock box
clock_box.showModal();
@@ -307,11 +304,10 @@
const shortcuts_span = document.createElement("span");
shortcuts_span.className = DateTimeShortcuts.shortCutsClass;
inp.parentNode.insertBefore(shortcuts_span, inp.nextSibling);
- const today_link = document.createElement("a");
- today_link.href = "#";
- today_link.role = "button";
- today_link.appendChild(document.createTextNode(gettext("Today")));
- today_link.setAttribute(
+ const today_button = document.createElement("button");
+ today_button.type = "button";
+ today_button.appendChild(document.createTextNode(gettext("Today")));
+ today_button.setAttribute(
"aria-label",
interpolate(
gettext("Today (%(date)s)"),
@@ -319,24 +315,24 @@
true,
),
);
- today_link.addEventListener("click", function (e) {
+ today_button.addEventListener("click", function (e) {
e.preventDefault();
DateTimeShortcuts.handleCalendarQuickLink(num, 0);
});
- const cal_link = document.createElement("button");
- cal_link.type = "button";
- cal_link.id = DateTimeShortcuts.calendarLinkName + num;
- cal_link.addEventListener("click", function (e) {
+ const cal_button = document.createElement("button");
+ cal_button.type = "button";
+ cal_button.id = DateTimeShortcuts.calendarButtonName + num;
+ cal_button.addEventListener("click", function (e) {
e.preventDefault();
// avoid triggering the document click handler to dismiss the calendar
e.stopPropagation();
DateTimeShortcuts.openCalendar(num);
});
const calIconId =
- DateTimeShortcuts.calendarLinkName + num + "_icon";
+ DateTimeShortcuts.calendarButtonName + num + "_icon";
quickElement(
"span",
- cal_link,
+ cal_button,
"",
"id",
calIconId,
@@ -345,13 +341,13 @@
"title",
gettext("Choose a Date"),
);
- cal_link.setAttribute("aria-labelledby", calIconId);
+ cal_button.setAttribute("aria-labelledby", calIconId);
shortcuts_span.appendChild(document.createTextNode("\u00A0"));
- shortcuts_span.appendChild(today_link);
+ shortcuts_span.appendChild(today_button);
shortcuts_span.appendChild(
document.createTextNode("\u00A0|\u00A0"),
);
- shortcuts_span.appendChild(cal_link);
+ shortcuts_span.appendChild(cal_button);
// Create calendarbox div.
//
@@ -360,26 +356,26 @@
//
//
- //
‹
- //
›
+ //
‹
+ //
›
//
//
//
//
//
//
- // Cancel
+ // Cancel
//
//
const cal_box = document.createElement("dialog");
@@ -393,9 +389,9 @@
});
// Handle arrow key navigation within the calendar
cal_box.addEventListener("keydown", function (event) {
- const focused = cal_box.querySelector("a:focus");
+ const focused = cal_box.querySelector("button:focus");
if (!focused) return;
- const cells = Array.from(cal_box.querySelectorAll("td a"));
+ const cells = Array.from(cal_box.querySelectorAll("td button"));
const currentIndex = cells.indexOf(focused);
if (currentIndex === -1) return;
@@ -433,14 +429,26 @@
});
// next-prev links
const cal_nav = quickElement("div", cal_box);
- const cal_nav_prev = quickElement("a", cal_nav, "<", "href", "#");
+ const cal_nav_prev = quickElement(
+ "button",
+ cal_nav,
+ "<",
+ "type",
+ "button",
+ );
cal_nav_prev.className = "calendarnav-previous";
cal_nav_prev.addEventListener("click", function (e) {
e.preventDefault();
DateTimeShortcuts.drawPrev(num);
});
- const cal_nav_next = quickElement("a", cal_nav, ">", "href", "#");
+ const cal_nav_next = quickElement(
+ "button",
+ cal_nav,
+ ">",
+ "type",
+ "button",
+ );
cal_nav_next.className = "calendarnav-next";
cal_nav_next.addEventListener("click", function (e) {
e.preventDefault();
@@ -465,16 +473,14 @@
// calendar shortcuts
const shortcuts = quickElement("div", cal_box);
shortcuts.className = "calendar-shortcuts";
- let day_link = quickElement(
- "a",
+ let day_button = quickElement(
+ "button",
shortcuts,
gettext("Yesterday"),
- "role",
+ "type",
"button",
- "href",
- "#",
);
- day_link.setAttribute(
+ day_button.setAttribute(
"aria-label",
interpolate(
gettext("Yesterday (%(date)s)"),
@@ -482,21 +488,19 @@
true,
),
);
- day_link.addEventListener("click", function (e) {
+ day_button.addEventListener("click", function (e) {
e.preventDefault();
DateTimeShortcuts.handleCalendarQuickLink(num, -1);
});
shortcuts.appendChild(document.createTextNode("\u00A0|\u00A0"));
- day_link = quickElement(
- "a",
+ day_button = quickElement(
+ "button",
shortcuts,
gettext("Today"),
- "role",
+ "type",
"button",
- "href",
- "#",
);
- day_link.setAttribute(
+ day_button.setAttribute(
"aria-label",
interpolate(
gettext("Today (%(date)s)"),
@@ -504,21 +508,19 @@
true,
),
);
- day_link.addEventListener("click", function (e) {
+ day_button.addEventListener("click", function (e) {
e.preventDefault();
DateTimeShortcuts.handleCalendarQuickLink(num, 0);
});
shortcuts.appendChild(document.createTextNode("\u00A0|\u00A0"));
- day_link = quickElement(
- "a",
+ day_button = quickElement(
+ "button",
shortcuts,
gettext("Tomorrow"),
- "role",
+ "type",
"button",
- "href",
- "#",
);
- day_link.setAttribute(
+ day_button.setAttribute(
"aria-label",
interpolate(
gettext("Tomorrow (%(date)s)"),
@@ -526,7 +528,7 @@
true,
),
);
- day_link.addEventListener("click", function (e) {
+ day_button.addEventListener("click", function (e) {
e.preventDefault();
DateTimeShortcuts.handleCalendarQuickLink(num, +1);
});
@@ -535,13 +537,11 @@
const cancel_p = quickElement("p", cal_box);
cancel_p.className = "calendar-cancel";
const cancel_link = quickElement(
- "a",
+ "button",
cancel_p,
gettext("Cancel"),
- "role",
+ "type",
"button",
- "href",
- "#",
);
cancel_link.addEventListener("click", function (e) {
e.preventDefault();
@@ -594,8 +594,8 @@
const cal_box = document.getElementById(
DateTimeShortcuts.calendarDivName1 + num,
);
- const cal_link = document.getElementById(
- DateTimeShortcuts.calendarLinkName + num,
+ const cal_button = document.getElementById(
+ DateTimeShortcuts.calendarButtonName + num,
);
const inp = DateTimeShortcuts.calendarInputs[num];
@@ -619,13 +619,13 @@
// Recalculate the calendarbox position
// is it left-to-right or right-to-left layout ?
if (window.getComputedStyle(document.body).direction !== "rtl") {
- cal_box.style.left = findPosX(cal_link) + 17 + "px";
+ cal_box.style.left = findPosX(cal_button) + 17 + "px";
} else {
// since style's width is in em, it'd be tough to calculate
// px value of it. let's use an estimated px for now
- cal_box.style.right = findPosX(cal_link) - 180 + "px";
+ cal_box.style.right = findPosX(cal_button) - 180 + "px";
}
- cal_box.style.top = Math.max(0, findPosY(cal_link) - 75) + "px";
+ cal_box.style.top = Math.max(0, findPosY(cal_button) - 75) + "px";
cal_box.showModal();
DateTimeShortcuts.updateNavAriaLabels(num);
@@ -635,9 +635,9 @@
if (calendarDiv) {
// Focus on selected date, today, or first available date
const focusElement =
- cal_box.querySelector("td.selected a") ||
- cal_box.querySelector("td.today a") ||
- cal_box.querySelector("td a");
+ cal_box.querySelector("td.selected button") ||
+ cal_box.querySelector("td.today button") ||
+ cal_box.querySelector("td button");
focusElement?.focus();
}
},
diff --git a/django/contrib/admin/static/admin/js/calendar.js b/django/contrib/admin/static/admin/js/calendar.js
index b9b45b26186b..457062b48432 100644
--- a/django/contrib/admin/static/admin/js/calendar.js
+++ b/django/contrib/admin/static/admin/js/calendar.js
@@ -223,14 +223,12 @@ depends on core.js for utility functions like removeChildren or quickElement
"class",
todayClass,
);
- const link = quickElement(
- "a",
+ const button = quickElement(
+ "button",
cell,
currentDay,
- "role",
+ "type",
"button",
- "href",
- "#",
);
let ariaLabel = CalendarNamespace.formatDate(
currentDay,
@@ -255,8 +253,8 @@ depends on core.js for utility functions like removeChildren or quickElement
ariaLabel,
]);
}
- link.setAttribute("aria-label", ariaLabel);
- link.addEventListener("click", calendarMonth(year, month));
+ button.setAttribute("aria-label", ariaLabel);
+ button.addEventListener("click", calendarMonth(year, month));
currentDay++;
}
diff --git a/django/contrib/admin/static/admin/js/inlines.js b/django/contrib/admin/static/admin/js/inlines.js
index 994425229503..174544cced0a 100644
--- a/django/contrib/admin/static/admin/js/inlines.js
+++ b/django/contrib/admin/static/admin/js/inlines.js
@@ -67,11 +67,11 @@
options.addCssClass +
'">
' +
+ '">' +
options.addText +
- " ",
+ "",
);
- addButton = $parent.find("tr:last a");
+ addButton = $parent.find("tr:last button");
} else {
// Otherwise, insert it immediately after the last form:
$this
@@ -79,11 +79,11 @@
.after(
'",
+ "",
);
- addButton = $this.filter(":last").next().find("a");
+ addButton = $this.filter(":last").next().find("button");
}
}
addButton.on("click", addInlineClickHandler);
@@ -138,35 +138,35 @@
// If the forms are laid out in table rows, insert
// the remove button into the last table cell:
row.children(":last").append(
- '",
+ "",
);
} else if (row.is("ul") || row.is("ol")) {
// If they're laid out as an ordered/unordered list,
// insert an after the last list item:
row.append(
- ' ' +
+ '">' +
options.deleteText +
- " ",
+ "",
);
} else {
// Otherwise, just insert the remove button as the
// last child element of the form's container:
row.children(":first").append(
- '' +
+ '">' +
options.deleteText +
- " ",
+ "",
);
}
// Add delete handler for each row.
- row.find("a." + options.deleteCssClass).on(
+ row.find("button." + options.deleteCssClass).on(
"click",
inlineDeleteHandler.bind(this),
);
diff --git a/django/contrib/admin/templates/admin/actions.html b/django/contrib/admin/templates/admin/actions.html
index ff2a5fe3d7ba..1987b5b51e4e 100644
--- a/django/contrib/admin/templates/admin/actions.html
+++ b/django/contrib/admin/templates/admin/actions.html
@@ -13,9 +13,9 @@
{% if cl.result_count != cl.result_list|length %}
{{ selection_note_all }}
- {% blocktranslate with cl.result_count as total_count %}Select all {{ total_count }} {{ module_name }}{% endblocktranslate %}
+ {% blocktranslate with cl.result_count as total_count %}Select all {{ total_count }} {{ module_name }}{% endblocktranslate %}
- {% translate "Clear selection" %}
+ {% translate "Clear selection" %}
{% endif %}
{% endif %}
{% endblock %}
diff --git a/django/contrib/admin/templates/admin/change_list_results.html b/django/contrib/admin/templates/admin/change_list_results.html
index bea4a5b859a5..d2a9feed2085 100644
--- a/django/contrib/admin/templates/admin/change_list_results.html
+++ b/django/contrib/admin/templates/admin/change_list_results.html
@@ -18,7 +18,7 @@
{% endif %}
- {% if header.sortable %}
{{ header.text|capfirst }} {% else %}
{{ header.text|capfirst }} {% endif %}
+ {% if header.sortable %}
{{ header.text|capfirst }} {% else %}
{{ header.text|capfirst }} {% endif %}
{% endfor %}
diff --git a/django/contrib/admin/templates/admin/delete_confirmation.html b/django/contrib/admin/templates/admin/delete_confirmation.html
index 7797f44eb394..c4d33bdb531c 100644
--- a/django/contrib/admin/templates/admin/delete_confirmation.html
+++ b/django/contrib/admin/templates/admin/delete_confirmation.html
@@ -44,7 +44,7 @@ {% translate "Objects" %}
{% if is_popup %} {% endif %}
{% if to_field %} {% endif %}
- {% translate "No, take me back" %}
+ {% translate "No, take me back" %}
{% endblock %}
diff --git a/django/contrib/admin/templates/admin/delete_selected_confirmation.html b/django/contrib/admin/templates/admin/delete_selected_confirmation.html
index cf503ec1230b..a9245d620df3 100644
--- a/django/contrib/admin/templates/admin/delete_selected_confirmation.html
+++ b/django/contrib/admin/templates/admin/delete_selected_confirmation.html
@@ -40,7 +40,7 @@ {% translate "Objects" %}
- {% translate "No, take me back" %}
+ {% translate "No, take me back" %}
{% endif %}
diff --git a/django/contrib/admin/templates/admin/submit_line.html b/django/contrib/admin/templates/admin/submit_line.html
index 5390dd36c167..b2b205496612 100644
--- a/django/contrib/admin/templates/admin/submit_line.html
+++ b/django/contrib/admin/templates/admin/submit_line.html
@@ -7,11 +7,11 @@
{% if show_save_and_continue %} {% endif %}
{% if show_close %}
{% url opts|admin_urlname:'changelist' as changelist_url %}
- {% translate 'Close' %}
+ {% translate 'Close' %}
{% endif %}
{% if show_delete_link and original %}
{% url opts|admin_urlname:'delete' original.pk|admin_urlquote as delete_url %}
- {% translate "Delete" %}
+ {% translate "Delete" %}
{% endif %}
{% endblock %}
diff --git a/django/contrib/admin/templatetags/admin_list.py b/django/contrib/admin/templatetags/admin_list.py
index a6adafabbefb..aa3e76fdd2fc 100644
--- a/django/contrib/admin/templatetags/admin_list.py
+++ b/django/contrib/admin/templatetags/admin_list.py
@@ -43,12 +43,12 @@ def paginator_number(cl, i):
return format_html("{} ", cl.paginator.ELLIPSIS)
elif i == cl.page_num:
return format_html(
- '{} ',
+ '{} ',
i,
)
else:
return format_html(
- '{} ',
+ '{} ',
cl.get_query_string({PAGE_VAR: i}),
i,
)
diff --git a/django/contrib/auth/templates/auth/widgets/read_only_password_hash.html b/django/contrib/auth/templates/auth/widgets/read_only_password_hash.html
index 102ceb30eb7d..a9b56a3331a2 100644
--- a/django/contrib/auth/templates/auth/widgets/read_only_password_hash.html
+++ b/django/contrib/auth/templates/auth/widgets/read_only_password_hash.html
@@ -1,5 +1,5 @@
{% load auth %}
diff --git a/js_tests/admin/DateTimeShortcuts.test.js b/js_tests/admin/DateTimeShortcuts.test.js
index 865aed2e6863..b03e2dfca543 100644
--- a/js_tests/admin/DateTimeShortcuts.test.js
+++ b/js_tests/admin/DateTimeShortcuts.test.js
@@ -23,7 +23,7 @@ QUnit.test("init", function (assert) {
const shortcuts = $(".datetimeshortcuts");
assert.equal(shortcuts.length, 1);
- assert.equal(shortcuts.find("a:first").text(), "Today");
+ assert.equal(shortcuts.find("button:first").text(), "Today");
assert.equal(shortcuts.find("button:last .date-icon").length, 1);
// To prevent incorrect timezone warnings on date/time widgets, timezoneOffset
@@ -39,7 +39,7 @@ QUnit.test("custom time shortcuts", function (assert) {
$("#qunit-fixture").append(timeField);
DateTimeShortcuts.clockHours.time_test = [["3 a.m.", 3]];
DateTimeShortcuts.init();
- assert.equal($(".clockbox").find("a").first().text(), "3 a.m.");
+ assert.equal($(".clockbox").find("button").first().text(), "3 a.m.");
});
QUnit.test("time zone offset warning - single field", function (assert) {
@@ -125,7 +125,7 @@ QUnit.test("today link has aria-label with current date", function (assert) {
);
$("#qunit-fixture").append(dateField);
DateTimeShortcuts.init();
- const todayLink = $(".datetimeshortcuts a:first");
+ const todayLink = $(".datetimeshortcuts button:first");
assert.equal(todayLink.text(), "Today");
// "Today (April 12, 2026)"
const today = new Date();
@@ -163,7 +163,7 @@ QUnit.test("calendar today highlight with server offset", function (assert) {
const todayCells = calDiv.find("td.today");
assert.equal(todayCells.length, 1, "Exactly one cell marked as today");
assert.equal(
- todayCells.find("a").text(),
+ todayCells.find("button").text(),
String(expectedDate.getDate()),
"Today cell matches server-adjusted date",
);
diff --git a/js_tests/admin/inlines.test.js b/js_tests/admin/inlines.test.js
index 28de67cf65c2..62b87842ca60 100644
--- a/js_tests/admin/inlines.test.js
+++ b/js_tests/admin/inlines.test.js
@@ -20,18 +20,18 @@ QUnit.module("admin.inlines: tabular formsets", {
QUnit.test("no forms", function (assert) {
assert.ok(this.inlineRow.hasClass("dynamic-first"));
- assert.equal(this.table.find(".add-row a").text(), this.addText);
+ assert.equal(this.table.find(".add-row button").text(), this.addText);
});
QUnit.test("add form", function (assert) {
- const addButton = this.table.find(".add-row a");
+ const addButton = this.table.find(".add-row button");
assert.equal(addButton.text(), this.addText);
addButton.click();
assert.ok(this.table.find("#first-1"));
});
QUnit.test("added form has remove button", function (assert) {
- const addButton = this.table.find(".add-row a");
+ const addButton = this.table.find(".add-row button");
assert.equal(addButton.text(), this.addText);
addButton.click();
assert.equal(this.table.find("#first-1 .inline-deletelink").length, 1);
@@ -39,7 +39,7 @@ QUnit.test("added form has remove button", function (assert) {
QUnit.test("add/remove form events", function (assert) {
assert.expect(5);
- const addButton = this.table.find(".add-row a");
+ const addButton = this.table.find(".add-row button");
document.addEventListener(
"formset:added",
(event) => {
@@ -75,7 +75,7 @@ QUnit.test("existing add button", function (assert) {
deleteText: "Remove",
addButton: addButton,
});
- assert.equal(this.table.find(".add-row a").length, 0);
+ assert.equal(this.table.find(".add-row button").length, 0);
addButton.click();
assert.ok(this.table.find("#first-1"));
});
@@ -126,7 +126,7 @@ QUnit.test(
const tr = this.inlineRows.slice(1, 2);
const trWithErrors = tr.prev();
assert.ok(trWithErrors.hasClass("row-form-errors"));
- const deleteLink = tr.find("a.inline-deletelink");
+ const deleteLink = tr.find("button.inline-deletelink");
deleteLink.trigger($.Event("click", { target: deleteLink }));
assert.notOk(this.table.find(".row-form-errors").length);
},
@@ -151,17 +151,17 @@ QUnit.module("admin.inlines: tabular formsets with max_num", {
QUnit.test(
"does not show the add button if already at max_num",
function (assert) {
- const addButton = this.table.find("tr.add_row > td > a");
+ const addButton = this.table.find("tr.add_row > td > button");
assert.notOk(addButton.is(":visible"));
},
);
QUnit.test("make addButton visible again", function (assert) {
const $ = django.jQuery;
- const addButton = this.table.find("tr.add_row > td > a");
+ const addButton = this.table.find("tr.add_row > td > button");
const removeButton = this.table
.find("tr.form-row:first")
- .find("a.inline-deletelink");
+ .find("button.inline-deletelink");
removeButton.trigger($.Event("click", { target: removeButton }));
assert.notOk(addButton.is(":visible"));
});
@@ -191,7 +191,7 @@ QUnit.test(
QUnit.test("make removeButtons visible again", function (assert) {
const $ = django.jQuery;
- const addButton = this.table.find("tr.add-row > td > a");
+ const addButton = this.table.find("tr.add-row > td > button");
addButton.trigger($.Event("click", { target: addButton }));
assert.equal(this.table.find(".inline-deletelink:visible").length, 2);
});
diff --git a/tests/admin_changelist/tests.py b/tests/admin_changelist/tests.py
index ba1f5d179365..f66d847dfe36 100644
--- a/tests/admin_changelist/tests.py
+++ b/tests/admin_changelist/tests.py
@@ -1053,11 +1053,11 @@ def test_pagination_render(self):
)
self.assertTrue(pagination_output.endswith(""))
self.assertInHTML(
- '1 ',
+ '1 ',
pagination_output,
)
self.assertInHTML(
- '2 ',
+ '2 ',
pagination_output,
)
self.assertEqual(pagination_output.count('aria-current="page"'), 1)
diff --git a/tests/admin_inlines/tests.py b/tests/admin_inlines/tests.py
index eda7c91310e9..5dcbbd669b47 100644
--- a/tests/admin_inlines/tests.py
+++ b/tests/admin_inlines/tests.py
@@ -1462,12 +1462,11 @@ def test_submit_line_shows_only_close_button(self):
response = self.client.get(self.change_url)
self.assertContains(
response,
- ''
- "Close ",
+ '' "Close ",
html=True,
)
delete_link = (
- 'Delete '
)
self.assertNotContains(response, delete_link % self.poll.id, html=True)
@@ -1908,7 +1907,7 @@ def test_add_stackeds(self):
self.assertCountSeleniumElements(rows_selector, 3)
add_button = self.selenium.find_element(
- By.LINK_TEXT, "Add another Inner4 stacked"
+ By.XPATH, "//button[contains(text(), 'Add another Inner4 stacked')]"
)
add_button.click()
self.assertCountSeleniumElements(rows_selector, 4)
@@ -1928,7 +1927,7 @@ def test_delete_stackeds(self):
self.assertCountSeleniumElements(rows_selector, 3)
add_button = self.selenium.find_element(
- By.LINK_TEXT, "Add another Inner4 stacked"
+ By.XPATH, "//button[contains(text(), 'Add another Inner4 stacked')]"
)
add_button.click()
add_button.click()
@@ -1956,8 +1955,8 @@ def test_delete_invalid_stacked_inlines(self):
self.assertCountSeleniumElements(rows_selector, 3)
add_button = self.selenium.find_element(
- By.LINK_TEXT,
- "Add another Inner4 stacked",
+ By.XPATH,
+ "//button[contains(text(), 'Add another Inner4 stacked')]",
)
add_button.click()
add_button.click()
@@ -2022,7 +2021,7 @@ def test_delete_invalid_tabular_inlines(self):
self.assertCountSeleniumElements(rows_selector, 3)
add_button = self.selenium.find_element(
- By.LINK_TEXT, "Add another Inner4 tabular"
+ By.XPATH, "//button[contains(text(), 'Add another Inner4 tabular')]"
)
add_button.click()
add_button.click()
@@ -2103,7 +2102,9 @@ def test_add_inlines(self):
)
# Add an inline
- self.selenium.find_element(By.LINK_TEXT, "Add another Profile").click()
+ self.selenium.find_element(
+ By.XPATH, "//button[contains(text(), 'Add another Profile')]"
+ ).click()
# The inline has been added, it has the right id, and it contains the
# correct fields.
@@ -2121,7 +2122,9 @@ def test_add_inlines(self):
".dynamic-profile_set#profile_set-1 input[name=profile_set-1-last_name]", 1
)
# Let's add another one to be sure
- self.selenium.find_element(By.LINK_TEXT, "Add another Profile").click()
+ self.selenium.find_element(
+ By.XPATH, "//button[contains(text(), 'Add another Profile')]"
+ ).click()
self.assertCountSeleniumElements(".dynamic-profile_set", 3)
self.assertEqual(
self.selenium.find_elements(By.CSS_SELECTOR, ".dynamic-profile_set")[
@@ -2186,7 +2189,9 @@ def test_add_inline_link_absent_for_view_only_parent_model(self):
self.selenium.get(self.live_server_url + change_url)
with self.disable_implicit_wait():
with self.assertRaises(NoSuchElementException):
- self.selenium.find_element(By.LINK_TEXT, "Add another Question")
+ self.selenium.find_element(
+ By.XPATH, "//button[contains(text(), 'Add another Question')]"
+ )
def test_delete_inlines(self):
from selenium.webdriver.common.by import By
@@ -2197,10 +2202,18 @@ def test_delete_inlines(self):
)
# Add a few inlines
- self.selenium.find_element(By.LINK_TEXT, "Add another Profile").click()
- self.selenium.find_element(By.LINK_TEXT, "Add another Profile").click()
- self.selenium.find_element(By.LINK_TEXT, "Add another Profile").click()
- self.selenium.find_element(By.LINK_TEXT, "Add another Profile").click()
+ self.selenium.find_element(
+ By.XPATH, "//button[contains(text(), 'Add another Profile')]"
+ ).click()
+ self.selenium.find_element(
+ By.XPATH, "//button[contains(text(), 'Add another Profile')]"
+ ).click()
+ self.selenium.find_element(
+ By.XPATH, "//button[contains(text(), 'Add another Profile')]"
+ ).click()
+ self.selenium.find_element(
+ By.XPATH, "//button[contains(text(), 'Add another Profile')]"
+ ).click()
self.assertCountSeleniumElements(
"#profile_set-group table tr.dynamic-profile_set", 5
)
@@ -2223,12 +2236,12 @@ def test_delete_inlines(self):
self.selenium.find_element(
By.CSS_SELECTOR,
"form#profilecollection_form tr.dynamic-profile_set#profile_set-1 "
- "td.delete a",
+ "td.delete button",
).click()
self.selenium.find_element(
By.CSS_SELECTOR,
"form#profilecollection_form tr.dynamic-profile_set#profile_set-2 "
- "td.delete a",
+ "td.delete button",
).click()
# The rows are gone and the IDs have been re-sequenced
self.assertCountSeleniumElements(
@@ -2281,7 +2294,9 @@ def test_added_stacked_inline_with_collapsed_fields(self):
self.live_server_url + reverse("admin:admin_inlines_teacher_add")
)
add_text = gettext("Add another %(verbose_name)s") % {"verbose_name": "Child"}
- self.selenium.find_element(By.LINK_TEXT, add_text).click()
+ self.selenium.find_element(
+ By.XPATH, f"//button[contains(text(), '{add_text}')]"
+ ).click()
test_fields = ["#id_child_set-0-name", "#id_child_set-1-name"]
summaries = self.selenium.find_elements(By.TAG_NAME, "summary")
self.assertEqual(len(summaries), 3)
@@ -2448,7 +2463,9 @@ def test_inlines_verbose_name(self):
self.assertIn("Available attendant", available.text)
self.assertIn("Chosen attendant", chosen.text)
# Added inline should also have the correct verbose_name.
- self.selenium.find_element(By.LINK_TEXT, "Add another Class").click()
+ self.selenium.find_element(
+ By.XPATH, "//button[contains(text(), 'Add another Class')]"
+ ).click()
available = self.selenium.find_element(
By.CSS_SELECTOR, css_available_selector % 1
)
@@ -2458,7 +2475,9 @@ def test_inlines_verbose_name(self):
self.assertIn("Available attendant", available.text)
self.assertIn("Chosen attendant", chosen.text)
# Third inline should also have the correct verbose_name.
- self.selenium.find_element(By.LINK_TEXT, "Add another Class").click()
+ self.selenium.find_element(
+ By.XPATH, "//button[contains(text(), 'Add another Class')]"
+ ).click()
available = self.selenium.find_element(
By.CSS_SELECTOR, css_available_selector % 2
)
@@ -2540,7 +2559,7 @@ def test_tabular_inline_delete_layout(self):
"fieldset.module tbody tr.dynamic-sighting_set:not(.original) td.delete",
)
self.assertIn(
- '',
+ '',
delete.get_attribute("innerHTML"),
)
self.take_screenshot("loaded")
diff --git a/tests/admin_views/test_autocomplete_view.py b/tests/admin_views/test_autocomplete_view.py
index d9595cdb286b..74c5358ef8cd 100644
--- a/tests/admin_views/test_autocomplete_view.py
+++ b/tests/admin_views/test_autocomplete_view.py
@@ -593,7 +593,9 @@ def assertNoResults(row):
self.assertEqual(len(rows), 3)
assertNoResults(rows[0])
# Autocomplete works in rows added using the "Add another" button.
- self.selenium.find_element(By.LINK_TEXT, "Add another Authorship").click()
+ self.selenium.find_element(
+ By.XPATH, "//button[contains(text(), 'Add another Authorship')]"
+ ).click()
rows = self.selenium.find_elements(By.CSS_SELECTOR, ".dynamic-authorship_set")
self.assertEqual(len(rows), 4)
assertNoResults(rows[-1])
diff --git a/tests/admin_views/tests.py b/tests/admin_views/tests.py
index af6bf07e98e8..f9fe58389b24 100644
--- a/tests/admin_views/tests.py
+++ b/tests/admin_views/tests.py
@@ -2875,7 +2875,7 @@ def test_change_view(self):
self.assertContains(response, "Extra form field: ")
self.assertContains(
response,
- 'Close ',
)
self.assertEqual(response.context["title"], "View article")
@@ -3043,7 +3043,7 @@ def test_change_view_without_object_change_permission(self):
self.assertContains(response, "View article ")
self.assertContains(
response,
- 'Close ',
)
@@ -6402,9 +6402,9 @@ def test_prepopulated_fields(self):
self.assertEqual(num_initial_select2_inputs, 4)
# Add an inline
- self.selenium.find_elements(By.LINK_TEXT, "Add another Related prepopulated")[
- 0
- ].click()
+ self.selenium.find_elements(
+ By.XPATH, "//button[contains(text(), 'Add another Related prepopulated')]"
+ )[0].click()
self.assertEqual(
len(self.selenium.find_elements(By.CLASS_NAME, "select2-selection")),
num_initial_select2_inputs + 2,
@@ -6465,7 +6465,7 @@ def test_prepopulated_fields(self):
# Add an inline
# Button may be outside the browser frame.
element = self.selenium.find_elements(
- By.LINK_TEXT, "Add another Related prepopulated"
+ By.XPATH, "//button[contains(text(), 'Add another Related prepopulated')]"
)[1]
self.selenium.execute_script("window.scrollTo(0, %s);" % element.location["y"])
element.click()
@@ -6496,9 +6496,9 @@ def test_prepopulated_fields(self):
# Add an inline without an initial inline.
# The button is outside of the browser frame.
self.selenium.execute_script("window.scrollTo(0, document.body.scrollHeight);")
- self.selenium.find_elements(By.LINK_TEXT, "Add another Related prepopulated")[
- 2
- ].click()
+ self.selenium.find_elements(
+ By.XPATH, "//button[contains(text(), 'Add another Related prepopulated')]"
+ )[2].click()
self.assertEqual(
len(self.selenium.find_elements(By.CLASS_NAME, "select2-selection")),
num_initial_select2_inputs + 6,
@@ -6523,12 +6523,10 @@ def test_prepopulated_fields(self):
self.assertEqual(slug1, "stacked-inline-2011-12-12")
self.assertEqual(slug2, "option-one")
# Add inline.
- add_link = self.selenium.find_elements(
- By.LINK_TEXT,
- "Add another Related prepopulated",
- )[3]
- self.selenium.execute_script("arguments[0].scrollIntoView();", add_link)
- add_link.click()
+ self.selenium.find_elements(
+ By.XPATH,
+ "//button[contains(text(), 'Add another Related prepopulated')]",
+ )[3].click()
row_id = "id_relatedprepopulated_set-4-1-"
self.selenium.find_element(By.ID, f"{row_id}pubdate").send_keys("1999-01-20")
status = self.selenium.find_element(By.ID, f"{row_id}status")
@@ -9056,7 +9054,7 @@ def test_change_view(self):
# Check the delete link.
delete_link = re.search(
- 'Delete ', response.text
+ 'Delete ', response.text
)
self.assertURLEqual(delete_link[1], self.get_delete_url())
@@ -9096,7 +9094,7 @@ def test_change_view_close_link(self):
self.client.force_login(viewuser)
response = self.client.get(self.get_change_url())
close_link = re.search(
- 'Close ', response.text
+ 'Close ', response.text
)
close_link = close_link[1].replace("&", "&")
self.assertURLEqual(close_link, self.get_changelist_url())
diff --git a/tests/admin_widgets/tests.py b/tests/admin_widgets/tests.py
index a607f1fedcd1..959855c06dd0 100644
--- a/tests/admin_widgets/tests.py
+++ b/tests/admin_widgets/tests.py
@@ -1020,7 +1020,7 @@ def test_show_hide_date_time_picker_widgets(self):
)
# First, with the date picker widget ---------------------------------
- cal_icon = self.selenium.find_element(By.ID, "calendarlink0")
+ cal_icon = self.selenium.find_element(By.ID, "calendarbutton0")
# The date picker is hidden
self.assertFalse(
self.selenium.find_element(By.ID, "calendarbox0").is_displayed()
@@ -1039,7 +1039,7 @@ def test_show_hide_date_time_picker_widgets(self):
)
# Click the calendar icon, then on the 15th of current month
cal_icon.click()
- self.selenium.find_element(By.XPATH, "//a[contains(text(), '15')]").click()
+ self.selenium.find_element(By.XPATH, "//button[contains(text(), '15')]").click()
self.assertFalse(
self.selenium.find_element(By.ID, "calendarbox0").is_displayed()
)
@@ -1049,7 +1049,7 @@ def test_show_hide_date_time_picker_widgets(self):
)
# Then, with the time picker widget ----------------------------------
- time_icon = self.selenium.find_element(By.ID, "clocklink0")
+ time_icon = self.selenium.find_element(By.ID, "clockbutton0")
# The time picker is hidden
self.assertFalse(self.selenium.find_element(By.ID, "clockbox0").is_displayed())
# Click the time icon
@@ -1060,7 +1060,7 @@ def test_show_hide_date_time_picker_widgets(self):
[
x.text
for x in self.selenium.find_elements(
- By.XPATH, "//ul[@class='timelist']/li/a"
+ By.XPATH, "//ul[@class='timelist']/li/button"
)
],
["Now", "Midnight", "6 a.m.", "Noon", "6 p.m."],
@@ -1071,7 +1071,9 @@ def test_show_hide_date_time_picker_widgets(self):
self.assertFalse(self.selenium.find_element(By.ID, "clockbox0").is_displayed())
# Click the time icon, then select the 'Noon' value
time_icon.click()
- self.selenium.find_element(By.XPATH, "//a[contains(text(), 'Noon')]").click()
+ self.selenium.find_element(
+ By.XPATH, "//button[contains(text(), 'Noon')]"
+ ).click()
self.assertFalse(self.selenium.find_element(By.ID, "clockbox0").is_displayed())
self.assertEqual(
self.selenium.find_element(By.ID, "id_birthdate_1").get_attribute("value"),
@@ -1095,7 +1097,7 @@ def test_calendar_nonday_class(self):
self.selenium.find_element(By.ID, "id_birthdate_0").send_keys("2013-06-01")
# Click the calendar icon
- self.selenium.find_element(By.ID, "calendarlink0").click()
+ self.selenium.find_element(By.ID, "calendarbutton0").click()
# get all the tds within the calendar
calendar0 = self.selenium.find_element(By.ID, "calendarin0")
@@ -1122,7 +1124,7 @@ def test_calendar_selected_class(self):
self.selenium.find_element(By.ID, "id_birthdate_0").send_keys("2013-06-01")
# Click the calendar icon
- self.selenium.find_element(By.ID, "calendarlink0").click()
+ self.selenium.find_element(By.ID, "calendarbutton0").click()
# get all the tds within the calendar
calendar0 = self.selenium.find_element(By.ID, "calendarin0")
@@ -1148,7 +1150,7 @@ def test_calendar_no_selected_class(self):
)
# Click the calendar icon
- self.selenium.find_element(By.ID, "calendarlink0").click()
+ self.selenium.find_element(By.ID, "calendarbutton0").click()
# get all the tds within the calendar
calendar0 = self.selenium.find_element(By.ID, "calendarin0")
@@ -1199,7 +1201,7 @@ def test_calendar_show_date_from_input(self):
# Open a page that has a date picker widget.
self.selenium.get(self.live_server_url + url)
# Click on the calendar icon.
- self.selenium.find_element(By.ID, "calendarlink0").click()
+ self.selenium.find_element(By.ID, "calendarbutton0").click()
# The right month and year are displayed.
self.wait_for_text("#calendarin0 caption", expected_caption)
@@ -1211,9 +1213,9 @@ def test_calendar_press_enter_focus_element(self):
self.selenium.get(
self.live_server_url + reverse("admin:admin_widgets_member_add")
)
- icon = self.selenium.find_element(By.ID, "calendarlink0")
+ icon = self.selenium.find_element(By.ID, "calendarbutton0")
expected_focus_element = self.selenium.find_element(
- By.CSS_SELECTOR, "div#calendarin0 table td.today a"
+ By.CSS_SELECTOR, "div#calendarin0 table td.today button"
)
icon.send_keys(Keys.ENTER)
focused_element = self.selenium.switch_to.active_element
@@ -1294,7 +1296,7 @@ def test_date_time_picker_shortcuts(self):
now = datetime.now()
for shortcut in shortcuts:
- shortcut.find_element(By.TAG_NAME, "a").click()
+ shortcut.find_element(By.TAG_NAME, "button").click()
# There is a time zone mismatch warning.
# Warning: This would effectively fail if the TIME_ZONE defined in the
diff --git a/tests/auth_tests/test_forms.py b/tests/auth_tests/test_forms.py
index 8af16696f0a3..f6d009ed8d75 100644
--- a/tests/auth_tests/test_forms.py
+++ b/tests/auth_tests/test_forms.py
@@ -1095,9 +1095,7 @@ def test_link_to_password_reset_in_user_change_form(self):
"Set password",
),
]
- password_reset_link = (
- r'([^<]*) '
- )
+ password_reset_link = r'([^<]*) '
for username, expected_help_text, expected_button_label in cases:
with self.subTest(username=username):
user = User.objects.get(username=username)
@@ -1452,7 +1450,7 @@ def test_render(self):
" hash : "
" WmCkn9************************************** "
" "
- ' '
+ ' '
"Reset password
"
"",
)
@@ -1462,7 +1460,7 @@ def test_render_no_password(self):
self.assertHTMLEqual(
widget.render("name", None, {}),
"",
)
@@ -1476,7 +1474,7 @@ def test_render_invalid_password_format(self):
widget.render("name", value, {}),
"",
)
diff --git a/tests/auth_tests/test_views.py b/tests/auth_tests/test_views.py
index 9baa6ddb5fb6..54fb9a107c19 100644
--- a/tests/auth_tests/test_views.py
+++ b/tests/auth_tests/test_views.py
@@ -1537,7 +1537,7 @@ def test_user_with_usable_password_change_password(self):
response = self.client.get(user_change_url)
# Test the link inside password field help_text.
rel_link = re.search(
- r' Reset password ',
+ r'Reset password ',
response.text,
)[1]
self.assertEqual(urljoin(user_change_url, rel_link), password_change_url)
@@ -1641,7 +1641,7 @@ def test_user_with_unusable_password_change_password(self):
response = self.client.get(user_change_url)
# Test the link inside password field help_text.
rel_link = re.search(
- r'Set password ',
+ r'Set password ',
response.text,
)[1]
self.assertEqual(urljoin(user_change_url, rel_link), password_change_url)
@@ -1733,7 +1733,7 @@ def test_view_user_password_is_readonly(self):
)
self.assertNotContains(
response,
- 'Reset password ',
+ 'Reset password ',
)
# Value in POST data is ignored.
data = self.get_user_data(u)