use super::*;
#[test]
fn html_area_element_global_and_instanceof_work() -> Result<()> {
let html = r#"
<map name='zones'>
<area id='hot' href='/go' alt='hot'>
</map>
<a id='link' href='/other'>other</a>
<p id='result'></p>
<script>
const hot = document.getElementById('hot');
const link = document.getElementById('link');
document.getElementById('result').textContent = [
typeof HTMLAreaElement,
window.HTMLAreaElement === HTMLAreaElement,
hot instanceof HTMLAreaElement,
hot instanceof HTMLElement,
link instanceof HTMLAreaElement
].join(':');
</script>
"#;
let h = Harness::from_html(html)?;
h.assert_text("#result", "function:true:true:true:false")?;
Ok(())
}
#[test]
fn area_properties_and_document_links_include_href_areas() -> Result<()> {
let html = r#"
<map name='primary'>
<area id='left' shape='circle' coords='75,75,75' href='/left' alt='Click left'>
<area id='noop' shape='default' alt='No link'>
</map>
<a id='other' href='/other'>other</a>
<button id='run'>run</button>
<p id='result'></p>
<script>
document.getElementById('run').addEventListener('click', () => {
const left = document.getElementById('left');
left.referrerPolicy = 'origin';
left.download = 'left.txt';
left.ping = 'https://ping.example';
document.getElementById('result').textContent =
left.href + '|' +
left.shape + '|' +
left.coords + '|' +
left.getAttribute('alt') + '|' +
left.referrerPolicy + '|' +
left.download + '|' +
left.ping + '|' +
document.links.length + '|' +
document.links[0].id + ':' + document.links[1].id;
});
</script>
"#;
let mut h = Harness::from_html_with_url("https://example.com/base/index.html", html)?;
h.click("#run")?;
h.assert_text(
"#result",
"https://example.com/left|circle|75,75,75|Click left|origin|left.txt|https://ping.example|2|left:other",
)?;
Ok(())
}
#[test]
fn area_click_follows_href_and_skips_blank_target_or_missing_href() -> Result<()> {
let html = r#"
<map name='routes'>
<area id='go' href='/go' alt='go'>
<area id='mail' href='mailto:m.bluth@example.com' alt='mail'>
<area id='inactive' href='/inactive' nohref alt='inactive'>
<area id='blank' href='/blank' target='_blank' alt='blank'>
<area id='nohref' alt='no href'>
</map>
"#;
let mut h = Harness::from_html_with_url("https://app.local/start", html)?;
h.click("#go")?;
h.click("#mail")?;
h.click("#inactive")?;
h.click("#blank")?;
h.click("#nohref")?;
assert_eq!(
h.take_location_navigations(),
vec![
LocationNavigation {
kind: LocationNavigationKind::Assign,
from: "https://app.local/start".to_string(),
to: "https://app.local/go".to_string(),
},
LocationNavigation {
kind: LocationNavigationKind::Assign,
from: "https://app.local/go".to_string(),
to: "mailto:m.bluth@example.com".to_string(),
},
]
);
Ok(())
}
#[test]
fn area_invalid_and_special_host_click_matrix_work() -> Result<()> {
let html = r#"
<map name='routes'>
<area id='bad' href='http://' alt='bad'>
<area id='bad-query' href='http:?x' alt='bad query'>
<area id='blank' href='https://example.com:abc/report' target='_blank' alt='blank'>
<area id='download' href='https://example.com:abc/report' download='report.txt' alt='download'>
<area id='inactive' href='https://example.com:abc/report' nohref alt='inactive'>
<area id='hostless' href='http:Example.COM:080/docs' alt='hostless'>
</map>
"#;
let mut h = Harness::from_html_with_url("https://app.local/start", html)?;
h.click("#bad")?;
h.click("#bad-query")?;
h.click("#blank")?;
h.click("#download")?;
h.click("#inactive")?;
h.click("#hostless")?;
assert_eq!(
h.take_location_navigations(),
vec![LocationNavigation {
kind: LocationNavigationKind::Assign,
from: "https://app.local/start".to_string(),
to: "http://example.com/docs".to_string(),
}]
);
Ok(())
}
#[test]
fn area_alt_nohref_interest_and_rel_list_properties_reflect_work() -> Result<()> {
let html = r#"
<map name='meta'>
<area id='spot' href='/x' alt='old alt' rel='noopener noreferrer'>
</map>
<button id='run'>run</button>
<p id='result'></p>
<script>
document.getElementById('run').addEventListener('click', () => {
const spot = document.getElementById('spot');
const before = [
spot.alt,
spot.noHref,
spot.relList.length
].join(':');
spot.alt = 'new alt';
spot.interestForElement = 'panel';
spot.noHref = true;
const withNoHref = [
spot.noHref,
spot.getAttribute('nohref') !== null
].join(':');
spot.noHref = false;
document.getElementById('result').textContent = [
before,
spot.alt,
spot.getAttribute('alt'),
spot.interestForElement,
withNoHref,
spot.noHref,
spot.getAttribute('nohref') === null,
spot.relList.length
].join('|');
});
</script>
"#;
let mut h = Harness::from_html(html)?;
h.click("#run")?;
h.assert_text(
"#result",
"old alt:false:2|new alt|new alt|panel|true:true|false|true|2",
)?;
Ok(())
}
#[test]
fn area_download_blob_click_captures_download_without_navigation() -> Result<()> {
let html = r#"
<map name='save'>
<area id='save-area' alt='save'>
</map>
<button id='prep'>prep</button>
<script>
document.getElementById('prep').addEventListener('click', () => {
const blob = new Blob(['abc'], { type: 'text/plain' });
const url = URL.createObjectURL(blob);
const area = document.getElementById('save-area');
area.href = url;
area.download = 'map.txt';
});
</script>
"#;
let mut h = Harness::from_html(html)?;
h.click("#prep")?;
h.click("#save-area")?;
assert!(h.take_location_navigations().is_empty());
assert_eq!(
h.take_downloads(),
vec![DownloadArtifact {
filename: Some("map.txt".to_string()),
mime_type: Some("text/plain".to_string()),
bytes: b"abc".to_vec(),
}]
);
Ok(())
}
#[test]
fn area_download_default_action_uses_post_click_attribute_state_and_keeps_network_downloads_uncaptured()
-> Result<()> {
let html = r#"
<map name='save'>
<area id='save-area' href='/initial' download='initial.txt' alt='save'>
</map>
<script>
let step = 0;
const live = URL.createObjectURL(new Blob(['area'], { type: 'text/plain' }));
const area = document.getElementById('save-area');
area.addEventListener('click', () => {
if (step === 0) {
area.href = live;
area.download = 'area.txt';
} else if (step === 1) {
area.href = '/report.csv';
area.download = 'network.txt';
} else {
area.href = '/done';
area.removeAttribute('download');
}
step += 1;
});
</script>
"#;
let mut h = Harness::from_html_with_url("https://app.local/start", html)?;
h.click("#save-area")?;
h.click("#save-area")?;
h.click("#save-area")?;
assert_eq!(
h.take_downloads(),
vec![DownloadArtifact {
filename: Some("area.txt".to_string()),
mime_type: Some("text/plain".to_string()),
bytes: b"area".to_vec(),
}]
);
assert_eq!(
h.take_location_navigations(),
vec![LocationNavigation {
kind: LocationNavigationKind::Assign,
from: "https://app.local/start".to_string(),
to: "https://app.local/done".to_string(),
}]
);
Ok(())
}
#[test]
fn area_role_is_link_with_href_and_empty_without_href() -> Result<()> {
let html = r#"
<map name='roles'>
<area id='hot' href='/x' alt='x'>
<area id='plain' alt='plain'>
</map>
<button id='run'>run</button>
<p id='result'></p>
<script>
document.getElementById('run').addEventListener('click', () => {
const hot = document.getElementById('hot');
const plain = document.getElementById('plain');
const initial = hot.role + ':' + plain.role;
plain.role = 'note';
const assigned = plain.role + ':' + plain.getAttribute('role');
plain.removeAttribute('role');
const restored = plain.role + ':' + (plain.getAttribute('role') === null);
document.getElementById('result').textContent =
initial + '|' + assigned + '|' + restored;
});
</script>
"#;
let mut h = Harness::from_html(html)?;
h.click("#run")?;
h.assert_text("#result", "link:|note:note|:true")?;
Ok(())
}
#[test]
fn area_url_and_hyperlink_properties_reflect_and_to_string_work() -> Result<()> {
let html = r#"
<map name='primary'>
<area id='left' href='/docs/p?x=1#h' alt='left'>
</map>
<button id='run'>run</button>
<p id='result'></p>
<script>
document.getElementById('run').addEventListener('click', () => {
location.href = 'https://example.com/base/index.html';
document.getElementById('left').download = 'left.txt';
document.getElementById('left').referrerPolicy = 'strict-origin';
document.getElementById('left').rel = 'noopener';
document.getElementById('left').target = '_blank';
document.getElementById('left').type = 'text/plain';
document.getElementById('left').ping = 'https://ping.example';
document.getElementById('left').shape = 'rect';
document.getElementById('left').coords = '0,0,10,10';
document.getElementById('result').textContent =
document.getElementById('left').href + '|' +
document.getElementById('left').protocol + '|' +
document.getElementById('left').host + '|' +
document.getElementById('left').pathname + '|' +
document.getElementById('left').search + '|' +
document.getElementById('left').hash + '|' +
document.getElementById('left').origin + '|' +
document.getElementById('left').download + '|' +
document.getElementById('left').referrerPolicy + '|' +
document.getElementById('left').rel + '|' +
document.getElementById('left').target + '|' +
document.getElementById('left').type + '|' +
document.getElementById('left').ping + '|' +
document.getElementById('left').shape + '|' +
document.getElementById('left').coords + '|' +
document.getElementById('left').toString();
});
</script>
"#;
let mut h = Harness::from_html(html)?;
h.click("#run")?;
h.assert_text(
"#result",
"https://example.com/docs/p?x=1#h|https:|example.com|/docs/p|?x=1|#h|https://example.com|left.txt|strict-origin|noopener|_blank|text/plain|https://ping.example|rect|0,0,10,10|https://example.com/docs/p?x=1#h",
)?;
Ok(())
}