mirror of
https://github.com/NetworkCats/rustyip.git
synced 2026-11-14 00:15:13 +00:00
fix: improve accessibility to meet WCAG 2.2 AA/AAA standards
- Remove disruptive alert() on error pages, rely on role="alert" banner - Add skip navigation link for keyboard users (WCAG 2.4.1) - Fix heading hierarchy on error page (sr-only status text in h1) - Add "opens in a new tab" screen reader hint on external links - Wrap language selector in form with noscript submit button (WCAG 3.2.2) - Add aria-label to copy-to-clipboard buttons and footer landmarks - Use h2 for alt-IP section to maintain single h1 per page - Add persistent underline on links for non-color identification (WCAG 1.4.1) - Fix footer attribution contrast ratio to ~5.5:1 (WCAG 1.4.3) - Add aria-busy/role=status loading announcements for skeleton state - Add translations for new accessibility strings across all 14 locales - Update integration tests to assert role="alert" instead of alert()
This commit is contained in:
@@ -191,3 +191,15 @@ msgstr "فشل عرض القالب"
|
||||
|
||||
msgid "Copied"
|
||||
msgstr "تم النسخ"
|
||||
|
||||
msgid "Go"
|
||||
msgstr "انتقال"
|
||||
|
||||
msgid "opens in a new tab"
|
||||
msgstr "يفتح في علامة تبويب جديدة"
|
||||
|
||||
msgid "Copy IP address to clipboard"
|
||||
msgstr "نسخ عنوان IP إلى الحافظة"
|
||||
|
||||
msgid "Site footer"
|
||||
msgstr "تذييل الموقع"
|
||||
|
||||
@@ -191,3 +191,15 @@ msgstr "Vorlagen-Rendering fehlgeschlagen"
|
||||
|
||||
msgid "Copied"
|
||||
msgstr "Kopiert"
|
||||
|
||||
msgid "Go"
|
||||
msgstr "Los"
|
||||
|
||||
msgid "opens in a new tab"
|
||||
msgstr "öffnet in neuem Tab"
|
||||
|
||||
msgid "Copy IP address to clipboard"
|
||||
msgstr "IP-Adresse in die Zwischenablage kopieren"
|
||||
|
||||
msgid "Site footer"
|
||||
msgstr "Seitenfuß"
|
||||
|
||||
@@ -191,3 +191,15 @@ msgstr "Template render failed"
|
||||
|
||||
msgid "Copied"
|
||||
msgstr "Copied"
|
||||
|
||||
msgid "Go"
|
||||
msgstr "Go"
|
||||
|
||||
msgid "opens in a new tab"
|
||||
msgstr "opens in a new tab"
|
||||
|
||||
msgid "Copy IP address to clipboard"
|
||||
msgstr "Copy IP address to clipboard"
|
||||
|
||||
msgid "Site footer"
|
||||
msgstr "Site footer"
|
||||
|
||||
@@ -191,3 +191,15 @@ msgstr "La renderizacion de la plantilla fallo"
|
||||
|
||||
msgid "Copied"
|
||||
msgstr "Copiado"
|
||||
|
||||
msgid "Go"
|
||||
msgstr "Ir"
|
||||
|
||||
msgid "opens in a new tab"
|
||||
msgstr "se abre en una pestaña nueva"
|
||||
|
||||
msgid "Copy IP address to clipboard"
|
||||
msgstr "Copiar dirección IP al portapapeles"
|
||||
|
||||
msgid "Site footer"
|
||||
msgstr "Pie de página"
|
||||
|
||||
@@ -191,3 +191,15 @@ msgstr "Echec du rendu du modele"
|
||||
|
||||
msgid "Copied"
|
||||
msgstr "Copie"
|
||||
|
||||
msgid "Go"
|
||||
msgstr "Aller"
|
||||
|
||||
msgid "opens in a new tab"
|
||||
msgstr "s'ouvre dans un nouvel onglet"
|
||||
|
||||
msgid "Copy IP address to clipboard"
|
||||
msgstr "Copier l'adresse IP dans le presse-papiers"
|
||||
|
||||
msgid "Site footer"
|
||||
msgstr "Pied de page"
|
||||
|
||||
@@ -191,3 +191,15 @@ msgstr "Render template gagal"
|
||||
|
||||
msgid "Copied"
|
||||
msgstr "Disalin"
|
||||
|
||||
msgid "Go"
|
||||
msgstr "Buka"
|
||||
|
||||
msgid "opens in a new tab"
|
||||
msgstr "dibuka di tab baru"
|
||||
|
||||
msgid "Copy IP address to clipboard"
|
||||
msgstr "Salin alamat IP ke papan klip"
|
||||
|
||||
msgid "Site footer"
|
||||
msgstr "Footer situs"
|
||||
|
||||
@@ -191,3 +191,15 @@ msgstr "Rendering del template fallito"
|
||||
|
||||
msgid "Copied"
|
||||
msgstr "Copiato"
|
||||
|
||||
msgid "Go"
|
||||
msgstr "Vai"
|
||||
|
||||
msgid "opens in a new tab"
|
||||
msgstr "si apre in una nuova scheda"
|
||||
|
||||
msgid "Copy IP address to clipboard"
|
||||
msgstr "Copia l'indirizzo IP negli appunti"
|
||||
|
||||
msgid "Site footer"
|
||||
msgstr "Piè di pagina"
|
||||
|
||||
@@ -191,3 +191,15 @@ msgstr "テンプレートのレンダリングに失敗しました"
|
||||
|
||||
msgid "Copied"
|
||||
msgstr "コピーしました"
|
||||
|
||||
msgid "Go"
|
||||
msgstr "移動"
|
||||
|
||||
msgid "opens in a new tab"
|
||||
msgstr "新しいタブで開きます"
|
||||
|
||||
msgid "Copy IP address to clipboard"
|
||||
msgstr "IPアドレスをクリップボードにコピー"
|
||||
|
||||
msgid "Site footer"
|
||||
msgstr "サイトフッター"
|
||||
|
||||
@@ -191,3 +191,15 @@ msgstr "템플릿 렌더링 실패"
|
||||
|
||||
msgid "Copied"
|
||||
msgstr "복사됨"
|
||||
|
||||
msgid "Go"
|
||||
msgstr "이동"
|
||||
|
||||
msgid "opens in a new tab"
|
||||
msgstr "새 탭에서 열림"
|
||||
|
||||
msgid "Copy IP address to clipboard"
|
||||
msgstr "IP 주소를 클립보드에 복사"
|
||||
|
||||
msgid "Site footer"
|
||||
msgstr "사이트 바닥글"
|
||||
|
||||
@@ -221,3 +221,19 @@ msgstr ""
|
||||
#: templates/base.html - language selector label
|
||||
msgid "Language"
|
||||
msgstr ""
|
||||
|
||||
#: templates/_footer_lang.html - language submit button (noscript)
|
||||
msgid "Go"
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html - ASN link new tab hint
|
||||
msgid "opens in a new tab"
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html - copy IP button label
|
||||
msgid "Copy IP address to clipboard"
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.html, error_alert.html - footer landmark label
|
||||
msgid "Site footer"
|
||||
msgstr ""
|
||||
|
||||
@@ -191,3 +191,15 @@ msgstr "Sjabloonweergave mislukt"
|
||||
|
||||
msgid "Copied"
|
||||
msgstr "Gekopieerd"
|
||||
|
||||
msgid "Go"
|
||||
msgstr "Ga"
|
||||
|
||||
msgid "opens in a new tab"
|
||||
msgstr "opent in een nieuw tabblad"
|
||||
|
||||
msgid "Copy IP address to clipboard"
|
||||
msgstr "IP-adres kopiëren naar klembord"
|
||||
|
||||
msgid "Site footer"
|
||||
msgstr "Sitefooter"
|
||||
|
||||
@@ -191,3 +191,15 @@ msgstr "Falha na renderização do template"
|
||||
|
||||
msgid "Copied"
|
||||
msgstr "Copiado"
|
||||
|
||||
msgid "Go"
|
||||
msgstr "Ir"
|
||||
|
||||
msgid "opens in a new tab"
|
||||
msgstr "abre em uma nova aba"
|
||||
|
||||
msgid "Copy IP address to clipboard"
|
||||
msgstr "Copiar endereço IP para a área de transferência"
|
||||
|
||||
msgid "Site footer"
|
||||
msgstr "Rodapé do site"
|
||||
|
||||
@@ -191,3 +191,15 @@ msgstr "Ошибка рендеринга шаблона"
|
||||
|
||||
msgid "Copied"
|
||||
msgstr "Скопировано"
|
||||
|
||||
msgid "Go"
|
||||
msgstr "Перейти"
|
||||
|
||||
msgid "opens in a new tab"
|
||||
msgstr "откроется в новой вкладке"
|
||||
|
||||
msgid "Copy IP address to clipboard"
|
||||
msgstr "Скопировать IP-адрес в буфер обмена"
|
||||
|
||||
msgid "Site footer"
|
||||
msgstr "Подвал сайта"
|
||||
|
||||
@@ -191,3 +191,15 @@ msgstr "模板渲染失败"
|
||||
|
||||
msgid "Copied"
|
||||
msgstr "已复制"
|
||||
|
||||
msgid "Go"
|
||||
msgstr "前往"
|
||||
|
||||
msgid "opens in a new tab"
|
||||
msgstr "在新标签页中打开"
|
||||
|
||||
msgid "Copy IP address to clipboard"
|
||||
msgstr "复制 IP 地址到剪贴板"
|
||||
|
||||
msgid "Site footer"
|
||||
msgstr "网站页脚"
|
||||
|
||||
@@ -191,3 +191,15 @@ msgstr "範本渲染失敗"
|
||||
|
||||
msgid "Copied"
|
||||
msgstr "已複製"
|
||||
|
||||
msgid "Go"
|
||||
msgstr "前往"
|
||||
|
||||
msgid "opens in a new tab"
|
||||
msgstr "在新分頁中開啟"
|
||||
|
||||
msgid "Copy IP address to clipboard"
|
||||
msgstr "複製 IP 位址到剪貼簿"
|
||||
|
||||
msgid "Site footer"
|
||||
msgstr "網站頁尾"
|
||||
|
||||
+22
-4
@@ -177,6 +177,8 @@ function initCopyIp(wrap) {
|
||||
wrap.style.cursor = "pointer";
|
||||
wrap.setAttribute("role", "button");
|
||||
wrap.setAttribute("tabindex", "0");
|
||||
const copyLabel = wrap.getAttribute("data-copy-label") || "Copy IP address to clipboard";
|
||||
wrap.setAttribute("aria-label", copyLabel);
|
||||
|
||||
const copyIp = () => {
|
||||
const ip = h1.textContent.trim();
|
||||
@@ -282,10 +284,11 @@ function initAltIp(root, section) {
|
||||
const copyWrap = document.createElement("div");
|
||||
copyWrap.className = "ip-copy-wrap";
|
||||
copyWrap.setAttribute("data-copied", copiedText);
|
||||
const h1 = document.createElement("h1");
|
||||
h1.className = "ip-display";
|
||||
h1.textContent = ip;
|
||||
copyWrap.appendChild(h1);
|
||||
copyWrap.setAttribute("data-copy-label", root.querySelector(".ip-copy-wrap")?.getAttribute("data-copy-label") || "Copy IP address to clipboard");
|
||||
const h2 = document.createElement("h2");
|
||||
h2.className = "ip-display";
|
||||
h2.textContent = ip;
|
||||
copyWrap.appendChild(h2);
|
||||
const tooltip = document.createElement("span");
|
||||
tooltip.className = "ip-copied-tooltip";
|
||||
tooltip.setAttribute("aria-live", "polite");
|
||||
@@ -314,6 +317,10 @@ function initAltIp(root, section) {
|
||||
a.target = "_blank";
|
||||
a.rel = "noopener noreferrer";
|
||||
a.textContent = `AS${asnNum}`;
|
||||
const newTabHint = document.createElement("span");
|
||||
newTabHint.className = "sr-only";
|
||||
newTabHint.textContent = ` (opens in a new tab)`;
|
||||
a.appendChild(newTabHint);
|
||||
td.appendChild(a);
|
||||
addRow(tbody, labelFor("asn"), td);
|
||||
}
|
||||
@@ -345,14 +352,24 @@ function initAltIp(root, section) {
|
||||
}
|
||||
|
||||
function showSkeleton() {
|
||||
section.setAttribute("aria-busy", "true");
|
||||
section.setAttribute("aria-label", "Loading additional IP information");
|
||||
section.setAttribute("role", "status");
|
||||
section.innerHTML = buildSkeleton();
|
||||
section.hidden = false;
|
||||
section.classList.add("alt-visible");
|
||||
}
|
||||
|
||||
function clearLoadingState() {
|
||||
section.removeAttribute("aria-busy");
|
||||
section.removeAttribute("aria-label");
|
||||
section.removeAttribute("role");
|
||||
}
|
||||
|
||||
function showAltIp(ip, info) {
|
||||
section.classList.remove("alt-visible");
|
||||
setTimeout(() => {
|
||||
clearLoadingState();
|
||||
section.replaceChildren(buildBlock(ip, info));
|
||||
initCopyIp(section.querySelector(".ip-copy-wrap"));
|
||||
scaleIpv6(section.querySelector(".ip-display"));
|
||||
@@ -372,6 +389,7 @@ function initAltIp(root, section) {
|
||||
function hideSkeleton() {
|
||||
section.classList.remove("alt-visible");
|
||||
setTimeout(() => {
|
||||
clearLoadingState();
|
||||
section.replaceChildren();
|
||||
section.hidden = true;
|
||||
}, 300);
|
||||
|
||||
+56
-8
@@ -81,6 +81,25 @@ main {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.skip-link {
|
||||
position: absolute;
|
||||
inset-inline-start: -9999px;
|
||||
inset-block-start: 0;
|
||||
z-index: 10000;
|
||||
padding: 8px 16px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #FFF;
|
||||
background: var(--color-blue);
|
||||
border-radius: 0 0 6px 6px;
|
||||
text-decoration: none;
|
||||
|
||||
&:focus {
|
||||
inset-inline-start: 50%;
|
||||
translate: -50% 0;
|
||||
}
|
||||
}
|
||||
|
||||
.search-form {
|
||||
display: flex;
|
||||
|
||||
@@ -207,10 +226,12 @@ main {
|
||||
|
||||
a {
|
||||
color: var(--color-link);
|
||||
text-decoration: none;
|
||||
text-decoration: underline;
|
||||
text-decoration-color: light-dark(rgb(0 122 255 / 0.4), rgb(9 132 255 / 0.4));
|
||||
text-underline-offset: 2px;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
text-decoration-color: currentColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -267,10 +288,12 @@ main {
|
||||
|
||||
a {
|
||||
color: var(--color-link);
|
||||
text-decoration: none;
|
||||
text-decoration: underline;
|
||||
text-decoration-color: light-dark(rgb(0 122 255 / 0.4), rgb(9 132 255 / 0.4));
|
||||
text-underline-offset: 2px;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
text-decoration-color: currentColor;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -406,10 +429,12 @@ main {
|
||||
|
||||
a {
|
||||
color: var(--color-link);
|
||||
text-decoration: none;
|
||||
text-decoration: underline;
|
||||
text-decoration-color: light-dark(rgb(0 122 255 / 0.4), rgb(9 132 255 / 0.4));
|
||||
text-underline-offset: 2px;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
text-decoration-color: currentColor;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -430,11 +455,11 @@ main {
|
||||
p {
|
||||
margin-block-end: 6px;
|
||||
font-size: 11px;
|
||||
color: var(--color-gray2);
|
||||
color: light-dark(#6E6E73, #9A9A9F);
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--color-gray2);
|
||||
color: light-dark(#6E6E73, #9A9A9F);
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
@@ -449,6 +474,9 @@ main {
|
||||
|
||||
.footer-lang {
|
||||
margin-block-start: 0;
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.lang-select {
|
||||
@@ -470,6 +498,26 @@ main {
|
||||
outline-offset: -1px;
|
||||
}
|
||||
}
|
||||
|
||||
.lang-submit {
|
||||
padding: 6px 12px;
|
||||
border: 1px solid var(--color-separator);
|
||||
border-radius: 6px;
|
||||
font-family: inherit;
|
||||
font-size: 13px;
|
||||
color: var(--color-label-secondary);
|
||||
background: var(--color-bg);
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background: var(--color-bg-secondary);
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
outline: 2px solid var(--color-blue);
|
||||
outline-offset: -1px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[dir="rtl"] .lang-select {
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
<div class="footer-lang">
|
||||
<form class="footer-lang" method="GET" action="/{{ lang_tag }}">
|
||||
<label for="lang-select" class="sr-only">{{ "Language"|t(locale) }}</label>
|
||||
<select id="lang-select" class="lang-select" autocomplete="off" onchange="if(this.value){var u=new(window.URL)(this.value,window.location.origin);u.search=window.location.search;window.location.href=u.href}">
|
||||
<select id="lang-select" name="lang" class="lang-select" autocomplete="off" onchange="if(this.value){var u=new(window.URL)(this.value,window.location.origin);u.search=window.location.search;window.location.href=u.href}">
|
||||
{% for l in all_locales %}
|
||||
<option value="/{{ l.tag() }}"{% if *l == locale %} selected{% endif %}>{{ l.name() }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<noscript><button type="submit" class="lang-submit">{{ "Go"|t(locale) }}</button></noscript>
|
||||
</form>
|
||||
+2
-1
@@ -19,7 +19,8 @@
|
||||
{% block head_extra %}{% endblock %}
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<a href="#main-content" class="skip-link">Skip to main content</a>
|
||||
<main id="main-content">
|
||||
{% block content %}{% endblock %}
|
||||
</main>
|
||||
{% block footer %}{% endblock %}
|
||||
|
||||
@@ -14,9 +14,7 @@
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/simple-line-icons/2.5.5/css/simple-line-icons.min.css">
|
||||
{% endblock %}
|
||||
|
||||
{% block head_extra %}
|
||||
<script>alert("{{ error_message }}");</script>
|
||||
{% endblock %}
|
||||
{% block head_extra %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% let autofocus = true %}
|
||||
@@ -32,7 +30,7 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block footer %}
|
||||
<footer class="site-footer">
|
||||
<footer class="site-footer" aria-label="{{ "Site footer"|t(locale) }}">
|
||||
<div class="footer-inner">
|
||||
<div class="footer-left">
|
||||
{% include "_footer.html" %}
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
|
||||
{% block content %}
|
||||
<div class="error-page">
|
||||
<h1 class="error-code">{{ status_code }}</h1>
|
||||
<p class="error-status">{{ status_text }}</p>
|
||||
<h1 class="error-code">{{ status_code }}<span class="sr-only"> - {{ status_text }}</span></h1>
|
||||
<p class="error-status" aria-hidden="true">{{ status_text }}</p>
|
||||
<p class="error-detail">{{ error_message }}</p>
|
||||
<a href="/{{ locale.tag() }}" class="error-home-link">{{ "Go to Home"|t(locale) }}</a>
|
||||
</div>
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
data-table-label="{{ "IP address information"|t(locale) }}"
|
||||
{% if is_query %}data-is-query="true"{% endif %}
|
||||
id="ip-info-root">
|
||||
<div class="ip-copy-wrap" data-copied="{{ "Copied"|t(locale) }}">
|
||||
<div class="ip-copy-wrap" data-copied="{{ "Copied"|t(locale) }}" data-copy-label="{{ "Copy IP address to clipboard"|t(locale) }}">
|
||||
<h1 class="ip-display" itemprop="name">{{ ip }}</h1>
|
||||
<span class="ip-copied-tooltip" aria-live="polite" hidden>{{ "Copied"|t(locale) }}</span>
|
||||
</div>
|
||||
@@ -82,7 +82,7 @@
|
||||
{% if !asn.is_empty() %}
|
||||
<tr data-label="asn">
|
||||
<th scope="row">{{ "ASN"|t(locale) }}</th>
|
||||
<td>{% if let Some(n) = asn_number %}<a href="https://bgp.tools/as/{{ n }}" target="_blank" rel="noopener noreferrer">{{ asn }}</a>{% else %}{{ asn }}{% endif %}</td>
|
||||
<td>{% if let Some(n) = asn_number %}<a href="https://bgp.tools/as/{{ n }}" target="_blank" rel="noopener noreferrer">{{ asn }}<span class="sr-only"> ({{ "opens in a new tab"|t(locale) }})</span></a>{% else %}{{ asn }}{% endif %}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% if !org.is_empty() %}
|
||||
@@ -274,7 +274,7 @@ curl {{ site_domain }}/tor</code></pre>
|
||||
{% endblock %}
|
||||
|
||||
{% block footer %}
|
||||
<footer class="site-footer">
|
||||
<footer class="site-footer" aria-label="{{ "Site footer"|t(locale) }}">
|
||||
<div class="footer-inner">
|
||||
<div class="footer-left">
|
||||
{% include "_footer.html" %}
|
||||
|
||||
@@ -916,7 +916,7 @@ async fn browser_invalid_ip_shows_alert_html() {
|
||||
.await;
|
||||
assert_eq!(status, StatusCode::BAD_REQUEST);
|
||||
assert!(body.contains("<!DOCTYPE html>"));
|
||||
assert!(body.contains("alert("));
|
||||
assert!(body.contains("role=\"alert\""));
|
||||
assert!(body.contains("not-an-ip"));
|
||||
}
|
||||
|
||||
@@ -934,7 +934,7 @@ async fn browser_non_public_ip_shows_alert_html() {
|
||||
.await;
|
||||
assert_eq!(status, StatusCode::BAD_REQUEST);
|
||||
assert!(body.contains("<!DOCTYPE html>"));
|
||||
assert!(body.contains("alert("));
|
||||
assert!(body.contains("role=\"alert\""));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -951,7 +951,7 @@ async fn browser_missing_client_ip_shows_alert_html() {
|
||||
.await;
|
||||
assert_eq!(status, StatusCode::BAD_REQUEST);
|
||||
assert!(body.contains("<!DOCTYPE html>"));
|
||||
assert!(body.contains("alert("));
|
||||
assert!(body.contains("role=\"alert\""));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -1367,7 +1367,7 @@ async fn browser_private_ipv4_shows_error() {
|
||||
.await;
|
||||
assert_eq!(status, StatusCode::BAD_REQUEST);
|
||||
assert!(body.contains("<!DOCTYPE html>"));
|
||||
assert!(body.contains("alert("));
|
||||
assert!(body.contains("role=\"alert\""));
|
||||
assert!(body.contains("192.168.1.1"));
|
||||
}
|
||||
|
||||
@@ -1384,7 +1384,7 @@ async fn browser_loopback_shows_error() {
|
||||
)
|
||||
.await;
|
||||
assert_eq!(status, StatusCode::BAD_REQUEST);
|
||||
assert!(body.contains("alert("));
|
||||
assert!(body.contains("role=\"alert\""));
|
||||
}
|
||||
|
||||
// --- IPv4 domain tests ---
|
||||
@@ -1582,5 +1582,5 @@ async fn browser_broadcast_shows_error() {
|
||||
)
|
||||
.await;
|
||||
assert_eq!(status, StatusCode::BAD_REQUEST);
|
||||
assert!(body.contains("alert("));
|
||||
assert!(body.contains("role=\"alert\""));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user