mesh/merge-gate head 6d7117a361b8 merged into trunk 43e0daf6947d — pass: builds brother → shanks; no bus step; every machine composes with the change as it…
mesh/repo-check head 6d7117a361b8 merged into trunk 43e0daf6947d — pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-…
mesh/delivery delivered
124 lines
5.6 KiB
Go
124 lines
5.6 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func fieldNamed(t *testing.T, p Page, name string) Field {
|
|
t.Helper()
|
|
for _, f := range p.Forms {
|
|
for _, fl := range f.Fields {
|
|
if fl.Name == name {
|
|
return fl
|
|
}
|
|
}
|
|
}
|
|
t.Fatalf("no field %s in %+v", name, p.Forms)
|
|
return Field{}
|
|
}
|
|
|
|
// 1530: a radio group is ONE field that answers the checked button's value, and every button is an option.
|
|
func TestARadioGroupIsOneFieldAnsweringTheCheckedButton(t *testing.T) {
|
|
p := ParsePage([]byte(`<form><table><tr><th>Mode</th><td>
|
|
<input type="radio" id="a" name="R" value="1"/><label for="a">Enabled</label>
|
|
<input type="radio" id="b" name="R" value="0" checked="checked"/><label for="b">Disabled</label></td></tr></table></form>`))
|
|
if n := len(p.Forms[0].Fields); n != 1 {
|
|
t.Fatalf("%d fields, want the radio group as one: %+v", n, p.Forms[0].Fields)
|
|
}
|
|
f := fieldNamed(t, p, "R")
|
|
if f.Type != "radio" || f.Value != "0" || f.Label != "Mode" {
|
|
t.Errorf("group = %+v", f)
|
|
}
|
|
if len(f.Options) != 2 || f.Options[0] != (Option{Value: "1", Label: "Enabled"}) || f.Options[1] != (Option{Value: "0", Label: "Disabled"}) {
|
|
t.Errorf("options = %+v", f.Options)
|
|
}
|
|
}
|
|
|
|
// 1530: a checkbox answers whether it is checked, both ways.
|
|
func TestACheckboxAnswersCheckedOrNot(t *testing.T) {
|
|
p := ParsePage([]byte(`<form><input type="checkbox" name="on" value="1" checked/><input type="checkbox" name="off" value="1"/></form>`))
|
|
on, off := fieldNamed(t, p, "on"), fieldNamed(t, p, "off")
|
|
if on.Checked == nil || !*on.Checked || off.Checked == nil || *off.Checked {
|
|
t.Errorf("on = %+v, off = %+v", on, off)
|
|
}
|
|
raw, _ := json.Marshal(off)
|
|
if !strings.Contains(string(raw), `"checked":false`) {
|
|
t.Errorf("an unchecked box says so in JSON: %s", raw)
|
|
}
|
|
}
|
|
|
|
// 1530: a select answers the selected option's value, else the first, with its options as value and text.
|
|
func TestASelectAnswersTheSelectedOptionElseTheFirst(t *testing.T) {
|
|
p := ParsePage([]byte(`<form><select name="s"><option value="0">English</option><option value="3" selected>Deutsch</option></select>
|
|
<select name="d"><option value="0">English</option><option value="3">Deutsch</option></select></form>`))
|
|
s, d := fieldNamed(t, p, "s"), fieldNamed(t, p, "d")
|
|
if s.Value != "3" || d.Value != "0" {
|
|
t.Errorf("selected %q, default %q", s.Value, d.Value)
|
|
}
|
|
if len(s.Options) != 2 || s.Options[1] != (Option{Value: "3", Text: "Deutsch"}) {
|
|
t.Errorf("options = %+v", s.Options)
|
|
}
|
|
}
|
|
|
|
// 1530: a field with no <label for> is labelled by its table row's first cell, or its <dt>.
|
|
func TestAFieldIsLabelledByItsTableRow(t *testing.T) {
|
|
p := ParsePage([]byte(`<form><table><tr><td>Sleep time</td><td><input type="text" name="B1"/></td></tr></table>
|
|
<dl><dt>Volume</dt><dd><input type="text" name="B2"/></dd></dl>
|
|
<table><tr><td><label for="c">Own</label></td><td><input id="c" type="text" name="B3"/></td></tr></table></form>`))
|
|
for name, want := range map[string]string{"B1": "Sleep time", "B2": "Volume", "B3": "Own"} {
|
|
if got := fieldNamed(t, p, name).Label; got != want {
|
|
t.Errorf("%s label = %q, want %q", name, got, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
// 1530: the scan-from-PC page, RECONSTRUCTED (its checked button and row heading are assumptions, only the form
|
|
// actions, field names, option labels and values come from the live answer): only its structure is asserted.
|
|
func TestTheReconstructedScanFromPCPageHasItsRadioGroupAsOneField(t *testing.T) {
|
|
p := ParsePage([]byte(adminFixture(t, "reconstructed-scanfrompc.html")))
|
|
if len(p.Forms) != 2 {
|
|
t.Fatalf("forms = %+v", p.Forms)
|
|
}
|
|
var radios []Field
|
|
for _, f := range p.Forms[1].Fields {
|
|
if f.Type == "radio" {
|
|
radios = append(radios, f)
|
|
}
|
|
}
|
|
if len(radios) != 1 || radios[0].Name != "B117d" || len(radios[0].Options) != 2 ||
|
|
radios[0].Options[0] != (Option{Value: "1", Label: "Enabled"}) || radios[0].Options[1] != (Option{Value: "0", Label: "Disabled"}) {
|
|
t.Errorf("radios = %+v", radios)
|
|
}
|
|
first := p.Forms[0]
|
|
if first.Action != "/home/status.html" || len(first.Fields) != 2 || first.Fields[0].Name != "CSRFToken" || first.Fields[1].Name != "B1892" {
|
|
t.Errorf("first form = %+v", first)
|
|
}
|
|
}
|
|
|
|
// 1530: a radio group with no checked button answers value "" and both options.
|
|
func TestARadioGroupWithNothingCheckedAnswersNoValue(t *testing.T) {
|
|
p := ParsePage([]byte(`<form><input type="radio" id="a" name="R" value="1"/><label for="a">On</label><input type="radio" id="b" name="R" value="0"/><label for="b">Off</label></form>`))
|
|
f := fieldNamed(t, p, "R")
|
|
if f.Value != "" || len(f.Options) != 2 {
|
|
t.Errorf("group = %+v", f)
|
|
}
|
|
}
|
|
|
|
// 1530: a label is never guessed from text that is not the field's: the text after a radio button, the text of
|
|
// another form, a menu link, a layout table's menu. The label is empty instead.
|
|
func TestAFieldIsNotLabelledByOtherTexts(t *testing.T) {
|
|
for name, c := range map[string]struct{ html, field string }{
|
|
"after a radio group": {`<form><input type="radio" name="R" value="1"/>Off<input type="text" name="X"/></form>`, "X"},
|
|
"after a label": {`<form><input type="radio" id="a" name="R" value="1"/><label for="a">Disabled</label><input type="text" name="X"/></form>`, "X"},
|
|
"in a second form": {`<form><input type="radio" name="R" value="1"/>Disabled</form><form><input type="text" name="X"/></form>`, "X"},
|
|
"after a menu link": {`<a href="/scan/scanfrompc.html">Scan from PC</a><form><input type="text" name="X"/></form>`, "X"},
|
|
"layout table menu": {`<table><tr><td><a href="/a">Menu</a><a href="/b">Status</a></td><td><form><input type="text" name="X"/></form></td></tr></table>`, "X"},
|
|
} {
|
|
if got := fieldNamed(t, ParsePage([]byte(c.html)), c.field).Label; got != "" {
|
|
t.Errorf("%s: label = %q, want none", name, got)
|
|
}
|
|
}
|
|
}
|