package webui import ( "strings" "testing" "kjol/wasmruntime/vdom" ) // The pad's value IS the markup it shows — that is the whole reason it draws into an SVG // rather than a canvas. If the two could differ, the user would sign one thing and the // caller would store another. func TestSignaturePadValueIsWhatIsDrawn(t *testing.T) { var got string pad := NewSignaturePad(SignaturePadOptions{OnChange: func(svg string) { got = svg }}) pad.strokes.Set([]sigStroke{{{X: 10, Y: 20}, {X: 30, Y: 40}, {X: 50, Y: 20}}}) value := pad.SVG() shown := vdom.RenderHTML(pad.Render(SignaturePadProps{})) // Every path in the value is present in the rendered element. paths := sigPaths(pad.strokes.Get()) if paths == "" { t.Fatal("no path was generated for a three-point stroke") } if !strings.Contains(value, paths) { t.Error("the emitted SVG does not contain the strokes it was built from") } if !strings.Contains(shown, `d="M10,20`) { t.Errorf("the rendered pad is not showing the stroke:\n%s", shown) } _ = got } // An empty pad is an empty string, not a blank drawing. A caller storing the value must // be able to ask "did they sign?" without parsing SVG. func TestSignaturePadEmptyIsEmptyString(t *testing.T) { pad := NewSignaturePad(SignaturePadOptions{}) if !pad.IsEmpty() { t.Error("a fresh pad should be empty") } if pad.SVG() != "" { t.Errorf("an empty pad produced %q, want \"\"", pad.SVG()) } } // Clear reports the emptiness to the caller. Without the callback a cleared pad would // leave the last signature sitting in whatever the caller stored it in. func TestSignaturePadClearNotifies(t *testing.T) { got := "not called" pad := NewSignaturePad(SignaturePadOptions{OnChange: func(svg string) { got = svg }}) pad.strokes.Set([]sigStroke{{{X: 1, Y: 1}, {X: 2, Y: 2}}}) pad.Clear() if got != "" { t.Errorf("OnChange got %q on clear, want \"\"", got) } if !pad.IsEmpty() { t.Error("the pad is not empty after Clear") } } // A single point is a tap, not a mark: it has no length, produces no path, and must not // count as a signature. func TestSignaturePadIgnoresSinglePointStrokes(t *testing.T) { if got := sigPaths([]sigStroke{{{X: 5, Y: 5}}}); got != "" { t.Errorf("a one-point stroke produced a path: %q", got) } } // Two points are a straight line; three or more are smoothed into curves. Handwriting // drawn as raw polylines looks like a seismograph. func TestSignaturePadSmoothsLongStrokes(t *testing.T) { line := sigPaths([]sigStroke{{{X: 0, Y: 0}, {X: 10, Y: 10}}}) if !strings.Contains(line, " L10,10") { t.Errorf("a two-point stroke should be a straight line: %q", line) } if strings.Contains(line, "Q") { t.Errorf("a two-point stroke has nothing to smooth: %q", line) } curve := sigPaths([]sigStroke{{{X: 0, Y: 0}, {X: 10, Y: 10}, {X: 20, Y: 0}}}) if !strings.Contains(curve, "Q") { t.Errorf("a three-point stroke should be smoothed: %q", curve) } }