| 1 | //go:build browser |
| 2 | |
| 3 | package check |
| 4 | |
| 5 | import ( |
| 6 | "context" |
| 7 | "math" |
| 8 | "testing" |
| 9 | "time" |
| 10 | |
| 11 | "github.com/chromedp/chromedp" |
| 12 | ) |
| 13 | |
| 14 | // TestATextareaGrowsWithWhatIsTypedInIt: rst-textarea is as tall as its |
| 15 | // text, from its 5rem minimum to half the viewport, and scrolls past |
| 16 | // that, so a long paste cannot push the rest of the form off the |
| 17 | // screen. Read in both spellings at 1280 with a mouse and 390 with |
| 18 | // touch: empty, two lines (still the minimum), a dozen (taller than |
| 19 | // the minimum, shorter than the cap) and two hundred (the cap, with the |
| 20 | // rest scrolled). |
| 21 | func TestATextareaGrowsWithWhatIsTypedInIt(t *testing.T) { |
| 22 | // markup-spelling: old-spelling begin — both spellings grow, and |
| 23 | // apps still write the class one. |
| 24 | body := `<div rst-page><textarea rst-textarea id="attr" name="a"></textarea><textarea class="rst-textarea" id="class" name="c"></textarea></div>` |
| 25 | // markup-spelling: old-spelling end |
| 26 | for _, leg := range []struct { |
| 27 | name string |
| 28 | w, h int64 |
| 29 | coarse bool |
| 30 | }{{"1280x900 mouse", 1280, 900, false}, {"390x844 touch", 390, 844, true}} { |
| 31 | t.Run(leg.name, func(t *testing.T) { |
| 32 | rig := sizingRig(t, leg.coarse, map[string]string{"/": sizingDoc("textarea", body)}) |
| 33 | ctx, cancel := context.WithTimeout(rig.Context(), 60*time.Second) |
| 34 | defer cancel() |
| 35 | mustRun(t, ctx, chromedp.EmulateViewport(leg.w, leg.h), chromedp.Navigate(rig.Origin+"/"), chromedp.WaitReady("#class", chromedp.ByQuery)) |
| 36 | requirePointer(t, ctx, leg.coarse) |
| 37 | for _, id := range []string{"attr", "class"} { |
| 38 | var g struct { |
| 39 | Min, Cap float64 |
| 40 | Empty, Few, Dozen, Many float64 |
| 41 | ManyScrolls, DozenScrolls bool |
| 42 | } |
| 43 | at(t, ctx, `(() => { |
| 44 | const ta = document.getElementById("`+id+`"), rem = parseFloat(getComputedStyle(document.documentElement).fontSize); |
| 45 | const h = n => { ta.value = Array.from({length: n}, (_, i) => "line " + (i + 1)).join("\n"); ta.dispatchEvent(new Event("input", {bubbles: true})); return ta.getBoundingClientRect().height; }; |
| 46 | const out = {Min: 5 * rem, Cap: innerHeight / 2, Empty: h(0), Few: h(2)}; |
| 47 | out.Dozen = h(12); out.DozenScrolls = ta.scrollHeight > ta.clientHeight + 1; |
| 48 | out.Many = h(200); out.ManyScrolls = ta.scrollHeight > ta.clientHeight + 1; |
| 49 | return JSON.stringify(out); |
| 50 | })()`, &g) |
| 51 | where := leg.name + " #" + id |
| 52 | if math.Abs(g.Empty-g.Min) > 0.5 || math.Abs(g.Few-g.Min) > 0.5 { |
| 53 | t.Errorf("%s: empty it is %.1fpx and with two lines %.1fpx; both should be the %.0fpx minimum", where, g.Empty, g.Few, g.Min) |
| 54 | } |
| 55 | if g.Dozen <= g.Min+0.5 || g.Dozen >= g.Cap || g.DozenScrolls { |
| 56 | t.Errorf("%s: with twelve lines it is %.1fpx (scrolls %v); it should grow past the %.0fpx minimum to fit them, under the %.0fpx cap", where, g.Dozen, g.DozenScrolls, g.Min, g.Cap) |
| 57 | } |
| 58 | if math.Abs(g.Many-g.Cap) > 0.5 || !g.ManyScrolls { |
| 59 | t.Errorf("%s: with two hundred lines it is %.1fpx (scrolls %v); it should stop at half the viewport, %.0fpx, and scroll", where, g.Many, g.ManyScrolls, g.Cap) |
| 60 | } |
| 61 | } |
| 62 | }) |
| 63 | } |
| 64 | } |
| 65 | |