Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HTML: Tests for button layout #14824

Merged
merged 1 commit into from
May 14, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<!doctype html>
<title>default style on buttons</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you link to the HTML spec PR from here? Or just adding links when it gets merged into the spec I guess.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The relevant section of the spec is supposed to be able to get from the last dir name for html, I think. Is that enough?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, that works, thanks :)

<div class="tests">
<input type="reset">
<input type="button">
<input type="submit">
<input type="color">
<button></button>
</div>
<script>
[].slice.call(document.querySelectorAll('.tests > *')).forEach(el => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: querySelectoAll should be iterable, so you can call forEach on it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah but it hasn't been for long (not sure it works cross-browser yet?), I didn't want to rely on newish features here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair :)

test(() => {
assert_equals(getComputedStyle(el).display, 'inline-block');
}, `default display on ${el.outerHTML}`);
test(() => {
assert_equals(getComputedStyle(el).boxSizing, 'border-box');
}, `default box-sizing on ${el.outerHTML}`);})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I'd move the }) to the next line.

</script>
31 changes: 31 additions & 0 deletions html/rendering/widgets/button-layout/abspos.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<!doctype html>
<title>abspos button with auto width, non-auto left/right</title>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<link rel=help href=https://html.spec.whatwg.org/multipage/rendering.html#button-layout>
<!--
If the element is absolutely positioned, then for the purpose of the CSS visual formatting model, act as if the element is a replaced element. [CSS]
-->
<link rel=help href=https://drafts.csswg.org/css2/visudet.html#abs-replaced-width>
<!--
If at this point the values are over-constrained, ignore the value for either 'left' (in case the 'direction' property of the containing block is 'rtl') or 'right' (in case 'direction' is 'ltr') and solve for that value.
-->
<style>
#overconstrained { position: absolute; left: 100px; right: 100px; }
#ltr { position: absolute; left: 100px; margin-top: 2em }
#rtl { position: absolute; right: 100px; margin-top: 2em }
</style>
<button id=overconstrained>test</button>
<button id=ltr>test</button>
<button id=rtl>test</button>
<script>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just double-checking, is there a WebKit / Blink bug on this test failing for rtl?

for (const dir of ['rtl', 'ltr']) {
test(() => {
document.documentElement.dir = dir;
const overconstrained = document.getElementById('overconstrained');
const ref = document.getElementById(dir);
assert_equals(overconstrained.offsetLeft, ref.offsetLeft, 'offsetLeft');
assert_equals(overconstrained.clientWidth, ref.clientWidth, 'clientWidth');
}, `${document.title} (${dir})`);
}
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<!doctype html>
<title>Reference for Anonymous button content box</title>
<style>
body { margin: 0 }
.button { width: 124px; height: 124px; background: papayawhip; border: 2px solid; display: table-cell; vertical-align: middle; text-align: center; box-sizing: border-box; }
.top { vertical-align: top }
.left { text-align: left }
.float { display: block; float: left; }
body > div { clear: left; }
.button > div { width: 50px; height: 50px; border: solid }
.button > .tall { height: 150px }
.button > .wide { width: 150px; margin-top: 32px }
</style>
<div>
<div class=button>input</div>
<div class="button">input grid</div>
<div class="button">input flex</div>
<div class=button>button</div>
</div>
<div>
<div class=button style="text-align: left">button left</div>
<div class=button><div>div</div></div>
<div class="button top">grid</div>
<div class="button top"><div>grid</div></div>
</div>
<div>
<div class="button top left float">flex</div>
<div class="button top float"><div>flex</div></div>
<div class="button float"><div class=tall>tall</div></div>
<div class="button float"><div class=wide>wide</div></div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<!doctype html>
<title>Anonymous button content box</title>
<link rel=match href=anonymous-button-content-box-ref.html>
<style>
body { margin: 0 }
button, input { width: 124px; height: 124px; background: papayawhip; border: 2px solid; margin: 0; padding: 0; float: left; font: inherit }
body > div { clear: left; }
button > div { width: 50px; height: 50px; border: solid }
.grid { display: grid }
.flex { display: flex }
.tall { height: 150px }
.wide { width: 150px }
</style>
<div>
<input type=button value=input>
<input type=button value="input grid" class=grid>
<input type=button value="input flex" class=flex>
<button>button</button>
</div>
<div>
<button style="text-align: left">button left</button>
<button><div>div</div></button>
<button class=grid>grid</button>
<button class=grid><div>grid</div></button>
</div>
<div>
<button class=flex>flex</button>
<button class=flex><div>flex</div></button>
<button><div class=tall>tall</div></button>
<button><div class=wide>wide</div></button>
</div>
31 changes: 31 additions & 0 deletions html/rendering/widgets/button-layout/computed-style.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<!doctype html>
<title>computed style on buttons</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div class="tests">
<input type="reset">
<input type="button">
<input type="submit">
<input type="color">
<button></button>
</div>
<script>
// "behave as" doesn't change computed value.
const displayValues = ['inline', 'block', 'list-item', 'inline-block', 'table', 'inline-table', 'table-row-group', 'table-header-group', 'table-footer-group', 'table-row', 'table-column-group', 'table-column', 'table-cell', 'table-caption', 'none', 'contents', 'flow', 'flow-root', 'flex', 'grid', 'ruby', 'ruby-base', 'ruby-text', 'ruby-base-container', 'ruby-text-container', 'inline-flex', 'inline-grid'];
for (const val of displayValues) {
[].slice.call(document.querySelectorAll('.tests > *')).forEach(el => {
el.style.display = ''
el.style.display = val;
const attrs = el.type ? ` type=${el.type}` : '';
const tag = `<${el.localName}${attrs}>`;
test(() => {
assert_not_equals(el.style.display, '', `display: ${val} is not supported`)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should skip the test if the display value is not supported?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, that makes it hard to reason about test results between browsers and over time.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair enough.

let expectedVal = val;
if (el instanceof HTMLInputElement && val === 'contents') {
expectedVal = 'none'; // https://drafts.csswg.org/css-display/#unbox-html
}
assert_equals(getComputedStyle(el).display, expectedVal);
}, `computed display of ${tag} with display: ${val}`);
});
}
</script>
52 changes: 52 additions & 0 deletions html/rendering/widgets/button-layout/display-other.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<!doctype html>
<title>button with other display values</title>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<style>
body { margin: 0 }
.float { width: 100px; height: 100px; float: left; background: blue; margin: 10px }
</style>
<div class=float></div>
<button id=button style="display: block;"><div class=float></div></button><span id=after>after</span>
<script>
// These should all behave as flow-root.
const displayValues = ['run-in', 'flow', 'flow-root', 'table', 'list-item',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nobody implements run-in, so maybe remove it from the list? Though not a huge deal otherwise I guess?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we remove it from the spec? Cc @tabatkins

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

run-in is still a useful tool (the use-cases from 20 years ago are just as valid today, and just as annoying to work around), and we editors believe it's specified in an implementable, useful way. I'd prefer not to let chicken-and-egg issues ruin this.

'table-row-group', 'table-header-group', 'table-footer-group',
'table-row', 'table-cell', 'table-column-group', 'table-column',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also nobody seems to pass the table parts tests re. offsetLeft / offsetRight, are we sure we really want to treat them as flow-root?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The table values also don't "work"... Not sure what actually happens but I figured this was close enough for web compat and still simple.

Or do offsetLeft/Top check computed value of display and have different behavior for table values?

'table-caption', 'ruby-base', 'ruby-text', 'ruby-base-container',
'ruby-text-container'];
const button = document.getElementById('button');
const after = document.getElementById('after');
function getValues() {
return {
buttonLeft: button.offsetLeft,
buttonTop: button.offsetTop,
buttonWidth: button.clientWidth,
buttonHeight: button.clientHeight,
afterLeft: after.offsetLeft,
afterTop: after.offsetTop,
};
}
const expected = getValues();
test(t => {
assert_equals(expected.buttonLeft, 120, 'buttonLeft');
assert_equals(expected.buttonTop, 0, 'buttonTop');
assert_greater_than_equal(expected.buttonWidth, 120, 'buttonWidth');
assert_greater_than_equal(expected.buttonHeight, 120, 'buttonHeight');
assert_equals(expected.afterLeft, 0, 'afterLeft');
assert_greater_than_equal(expected.afterTop, 120, 'afterTop');
}, 'display: block');
for (const val of displayValues) {
test(t => {
t.add_cleanup(() => {
button.style.display = 'block';
});
assert_true(CSS.supports(`display: ${val}`), `display: ${val} is not supported`);
button.style.display = val;
const values = getValues();
for (const prop in values) {
assert_equals(values[prop], expected[prop], prop);
}
}, `display: ${val}`);
}
</script>
29 changes: 29 additions & 0 deletions html/rendering/widgets/button-layout/flex.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<!doctype html>
<title>button with flex/inline-flex</title>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<style>
#inline-flex { display: inline-flex }
#flex { display: flex }
#ref > div { display: flex }
</style>
<button id=inline-flex><div>1</div><div>2</div><div>3</div><div>4</div></button>
<button id=flex><div>1</div><div>2</div><div>3</div><div>4</div></button>
<button id=ref><div><div>1</div><div>2</div><div>3</div><div>4</div></div></button>
<script>
const ref = document.getElementById('ref');
const expectedWidth = ref.clientWidth;
const expectedHeight = ref.clientHeight;
for (const elm of [document.getElementById('inline-flex'),
document.getElementById('flex')]) {
test(() => {
// check that flex is supported
const flexValue = elm.id;
assert_equals(getComputedStyle(elm).display, flexValue, `${flexValue} is not supported`);
const width = elm.clientWidth;
const height = elm.clientHeight;
assert_equals(width, expectedWidth, 'clientWidth');
assert_equals(height, expectedHeight, 'clientHeight');
}, elm.id);
}
</script>
30 changes: 30 additions & 0 deletions html/rendering/widgets/button-layout/grid.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<!doctype html>
<title>button with grid/inline-grid</title>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<style>
#inline-grid { display: inline-grid }
#grid { display: grid }
#ref > div { display: grid }
#inline-grid, #grid, #ref > div { grid-template: auto auto / auto auto }
</style>
<button id=inline-grid><div>1</div><div>2</div><div>3</div><div>4</div></button>
<button id=grid><div>1</div><div>2</div><div>3</div><div>4</div></button>
<button id=ref><div><div>1</div><div>2</div><div>3</div><div>4</div></div></button>
<script>
const ref = document.getElementById('ref');
const expectedWidth = ref.clientWidth;
const expectedHeight = ref.clientHeight;
for (const elm of [document.getElementById('inline-grid'),
document.getElementById('grid')]) {
test(() => {
// check that grid is supported
const gridValue = elm.id;
assert_equals(getComputedStyle(elm).display, gridValue, `${gridValue} is not supported`);
const width = elm.clientWidth;
const height = elm.clientHeight;
assert_equals(width, expectedWidth, 'clientWidth');
assert_equals(height, expectedHeight, 'clientHeight');
}, elm.id);
}
</script>
10 changes: 10 additions & 0 deletions html/rendering/widgets/button-layout/inline-level-ref.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<!doctype html>
<title>Reference for button with inline-level display</title>
<style>
button { font: inherit }
</style>
<p>There should be three buttons below containing "1" and "2" on separate lines, and "a" and "b" before and after on the same baseline as the "2".</p>
<p>a<button>1<br>2</button>b</p>
<p>a<button>1<br>2</button>b</p>
<p>a<button>1<br>2</button>b</p>
<p>a<button>1<br>2</button>b</p>
25 changes: 25 additions & 0 deletions html/rendering/widgets/button-layout/inline-level.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<!doctype html>
<title>button with inline-level display</title>
<link rel=match href=inline-level-ref.html>
<style>
button, input { font: inherit }
.inline { display: inline }
.inline-block { display: inline-block }
.inline-table { display: inline-table }
</style>
<p>There should be three buttons below containing "1" and "2" on separate lines, and "a" and "b" before and after on the same baseline as the "2".</p>
<p>a<button class=inline>1<br><span class=check-baseline>2</span></button><span class=ref-baseline>b</span></p>
<p>a<button class=inline-block>1<br><span class=check-baseline>2</span></button><span class=ref-baseline>b</span></p>
<p>a<button class=inline-table>1<br><span class=check-baseline>2</span></button><span class=ref-baseline>b</span></p>
<p>a<input type=button class=inline-table value="1&#10;2">b</p>
<script>
const spans = document.querySelectorAll('.check-baseline');
for (const span of [].slice.call(spans)) {
const baseline = span.offsetTop + span.offsetHeight;
const refSpan = span.parentNode.nextSibling;
const refBaseline = refSpan.offsetTop + refSpan.offsetHeight;
if (baseline !== refBaseline) {
refSpan.textContent += " (wrong baseline)";
}
}
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<!DOCTYPE html>
<title>Reference for propagating text-decoration into buttons</title>
<style>
button { font: inherit }
</style>
<p>The text in the following buttons should be underlined.</p>
<p><button><u>foo</u></button><button><u>foo</u></button></p>
<p>The text in the following buttons should NOT be underlined.</p>
<p><button>foo</button><button>foo</button></p>
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!DOCTYPE html>
<title>propagating text-decoration into buttons</title>
<link rel=match href=propagate-text-decoration-ref.html>
<style>
button, input { font: inherit }
.inline > u > * { display: inline }
.inline-block > u > * { display: inline-block }
</style>
<p>The text in the following buttons should be underlined.</p>
<p class=inline><u><button>foo</button><input type=button value=foo></u></p>
<p>The text in the following buttons should NOT be underlined.</p>
<p class=inline-block><u><button>foo</button><input type=button value=foo></u></p>
42 changes: 42 additions & 0 deletions html/rendering/widgets/button-layout/shrink-wrap.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<!doctype html>
<title>shrink-wrap button</title>
<link rel=help href=https://html.spec.whatwg.org/multipage/rendering.html#button-layout>
<link rel=help href=https://drafts.csswg.org/css2/visudet.html#shrink-to-fit-float>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<!--
minimum preferred width 100px
preferred width 250px
available width vary
-->
<style>
div.available-width { border: thin dotted red; margin: 1em 0; padding: 1em 0 }
button { border: none; margin: 0; padding: 0; background: papayawhip; }
button > span.minimum-preferred-width { width: 100px }
button > span { width: 50px; display: inline-block; outline: thin dotted blue }
</style>
<div class="available-width" style="width: 50px">
<button data-expected="100"><span class="minimum-preferred-width">x</span><span>x</span><span>x</span><span>x</span></button>
</div>

<div class="available-width" style="width: 200px">
<button data-expected="200"><span class="minimum-preferred-width">x</span><span>x</span><span>x</span><span>x</span></button>
</div>

<div class="available-width" style="width: 300px">
<button data-expected="250"><span class="minimum-preferred-width">x</span><span>x</span><span>x</span><span>x</span></button>
</div>

<script>
const styles = ['display: block', 'display: inline', 'display: inline-block',
'display: list-item', 'display: table', 'display: table-row',
'display: table-cell', 'float: left'];
for (const style of styles) {
for (const button of [].slice.call(document.querySelectorAll('button'))) {
test(() => {
button.setAttribute('style', style);
assert_equals(button.clientWidth, parseInt(button.dataset.expected, 10));
}, `${style} - available ${button.parentNode.getAttribute('style')}`);
}
}
</script>