AtlatestRepositorysigil-web

sigil-web / tree / testtest-ui.sgl

1(import (sigil test)
2 (sigil string)
3 (sigil sxml)
4 (sigil web ui)
5 (sigil http response))
6
7;; ============================================================
8;; sse-morph
9;; ============================================================
11(test-group "sse-morph"
12 (test "string content"
13 (let ((event (sse-morph target: "#chat" content: "<p>hello</p>")))
14 (assert-true (string-contains? event "event: sigil:morph"))
15 (assert-true (string-contains? event "data: target #chat"))
16 (assert-true (string-contains? event "data: mode morph"))
17 (assert-true (string-contains? event "data: html <p>hello</p>"))))
19 (test "SXML content"
20 (let ((event (sse-morph target: "#box" content: '(div "hi"))))
21 (assert-true (string-contains? event "data: html <div>hi</div>"))))
23 (test "append mode"
24 (let ((event (sse-morph target: "#list" mode: "append" content: "<li>new</li>")))
25 (assert-true (string-contains? event "data: mode append"))))
27 (test "with settle"
28 (let ((event (sse-morph target: "#x" content: "y" settle: 300)))
29 (assert-true (string-contains? event "data: settle 300"))))
31 (test "without settle"
32 (let ((event (sse-morph target: "#x" content: "y")))
33 (assert-false (string-contains? event "settle")))))
35;; ============================================================
36;; sse-remove
37;; ============================================================
39(test-group "sse-remove"
40 (test "generates remove morph event"
41 (let ((event (sse-remove target: "#notification")))
42 (assert-true (string-contains? event "event: sigil:morph"))
43 (assert-true (string-contains? event "data: target #notification"))
44 (assert-true (string-contains? event "data: mode remove")))))
46;; ============================================================
47;; sse-class
48;; ============================================================
50(test-group "sse-class"
51 (test "add classes"
52 (let ((event (sse-class target: "#panel" add: "visible active")))
53 (assert-true (string-contains? event "event: sigil:class"))
54 (assert-true (string-contains? event "data: target #panel"))
55 (assert-true (string-contains? event "data: add visible active"))))
57 (test "remove classes"
58 (let ((event (sse-class target: "#btn" remove: "loading")))
59 (assert-true (string-contains? event "data: remove loading"))
60 (assert-false (string-contains? event "data: add"))))
62 (test "add and remove"
63 (let ((event (sse-class target: "#x" add: "done" remove: "loading")))
64 (assert-true (string-contains? event "data: add done"))
65 (assert-true (string-contains? event "data: remove loading")))))
67;; ============================================================
68;; sse-eval
69;; ============================================================
71(test-group "sse-eval"
72 (test "basic event"
73 (let ((event (sse-eval cmd: "focus" target: "#input")))
74 (assert-true (string-contains? event "event: sigil:eval"))
75 (assert-true (string-contains? event "data: cmd focus"))
76 (assert-true (string-contains? event "data: target #input"))))
78 (test "with position"
79 (let ((event (sse-eval cmd: "scroll-to" target: "#chat" position: "bottom")))
80 (assert-true (string-contains? event "data: position bottom"))))
82 (test "without position"
83 (let ((event (sse-eval cmd: "focus" target: "#x")))
84 (assert-false (string-contains? event "position")))))
86;; ============================================================
87;; sse-redirect
88;; ============================================================
90(test-group "sse-redirect"
91 (test "basic redirect event"
92 (let ((event (sse-redirect url: "/login")))
93 (assert-true (string-contains? event "event: sigil:redirect"))
94 (assert-true (string-contains? event "data: url /login")))))
96;; ============================================================
97;; sse-reload
98;; ============================================================
100(test-group "sse-reload"
101 (test "default target is body"
102 (let ((event (sse-reload)))
103 (assert-true (string-contains? event "event: sigil:reload"))
104 (assert-true (string-contains? event "data: target body"))))
106 (test "custom target"
107 (let ((event (sse-reload target: "#main")))
108 (assert-true (string-contains? event "event: sigil:reload"))
109 (assert-true (string-contains? event "data: target #main"))))
111 (test "ends with blank line"
112 (let ((event (sse-reload)))
113 (assert-true (string-ends-with? event "\n\n")))))
115;; ============================================================
116;; sigil-ui-response
117;; ============================================================
119(test-group "sigil-ui-response"
120 (test "creates HTML response with merge headers"
121 (let ((res (sigil-ui-response target: "#main" content: "<p>hi</p>")))
122 (assert-equal 200 (http-response-status res))
123 (assert-equal "<p>hi</p>" (http-response-body res))
124 (assert-equal "#main"
125 (dict-ref (http-response-headers res) Sigil-UI-Merge-Target:))
126 (assert-equal "morph"
127 (dict-ref (http-response-headers res) Sigil-UI-Merge-Mode:))))
129 (test "custom status"
130 (let ((res (sigil-ui-response target: "#x" content: "err" status: 422)))
131 (assert-equal 422 (http-response-status res))))
133 (test "SXML conversion"
134 (let ((res (sigil-ui-response target: "#x" content: '(span "hi"))))
135 (assert-equal "<span>hi</span>" (http-response-body res)))))
137;; ============================================================
138;; sigil-ui-redirect
139;; ============================================================
141(test-group "sigil-ui-redirect"
142 (test "302 with location and UI redirect header"
143 (let ((res (sigil-ui-redirect url: "/dashboard")))
144 (assert-equal 302 (http-response-status res))
145 (assert-equal "/dashboard"
146 (dict-ref (http-response-headers res) location:))
147 (assert-equal "/dashboard"
148 (dict-ref (http-response-headers res) Sigil-UI-Redirect:)))))
150;; ============================================================
151;; sse-response-batch
152;; ============================================================
154(test-group "sse-response-batch"
155 (test "combines events with correct content-type"
156 (let* ((e1 (sse-morph target: "#a" content: "x"))
157 (e2 (sse-eval cmd: "focus" target: "#b"))
158 (res (sse-response-batch e1 e2)))
159 (assert-equal 200 (http-response-status res))
160 (assert-equal "text/event-stream"
161 (dict-ref (http-response-headers res) content-type:))
162 (assert-true (string-contains? (http-response-body res) "sigil:morph"))
163 (assert-true (string-contains? (http-response-body res) "sigil:eval")))))
165;; ============================================================
166;; sg-button
167;; ============================================================
169(test-group "sg-button"
170 (test "basic SXML"
171 (let ((sxml (sg-button "Like" action: "/api/like")))
172 (assert-equal "button" (symbol->string (car sxml)))
173 (let ((html (sxml->xml sxml)))
174 (assert-true (string-contains? html "data-sg-action=\"/api/like\""))
175 (assert-true (string-contains? html "Like")))))
177 (test "optional target attr"
178 (let ((html (sxml->xml (sg-button "X" action: "/x" target: "#res"))))
179 (assert-true (string-contains? html "data-sg-target=\"#res\""))))
181 (test "optional loading attr"
182 (let ((html (sxml->xml (sg-button "X" action: "/x" loading: "opacity-50"))))
183 (assert-true (string-contains? html "data-sg-loading=\"opacity-50\""))))
185 (test "optional confirm attr"
186 (let ((html (sxml->xml (sg-button "X" action: "/x" confirm: "Sure?"))))
187 (assert-true (string-contains? html "data-sg-confirm=\"Sure?\"")))))
189;; ============================================================
190;; sg-link
191;; ============================================================
193(test-group "sg-link"
194 (test "basic link with href and data-sg-action"
195 (let ((html (sxml->xml (sg-link '("Click") action: "/page"))))
196 (assert-true (string-contains? html "href=\"/page\""))
197 (assert-true (string-contains? html "data-sg-action=\"/page\""))
198 (assert-true (string-contains? html "Click"))))
200 (test "string children"
201 (let ((html (sxml->xml (sg-link "Click here" action: "/page"))))
202 (assert-true (string-contains? html "Click here")))))
204;; ============================================================
205;; sg-form
206;; ============================================================
208(test-group "sg-form"
209 (test "form with action and method"
210 (let ((html (sxml->xml (sg-form '() action: "/login" method: "post"))))
211 (assert-true (string-contains? html "data-sg-action=\"/login\""))
212 (assert-true (string-contains? html "data-sg-method=\"post\""))))
214 (test "form with error target"
215 (let ((html (sxml->xml (sg-form '() action: "/x" error-target: "#errors"))))
216 (assert-true (string-contains? html "data-sg-error=\"#errors\"")))))
218;; ============================================================
219;; sg-sse
220;; ============================================================
222(test-group "sg-sse"
223 (test "SSE container div"
224 (let ((html (sxml->xml (sg-sse '() url: "/events" id: "chat"))))
225 (assert-true (string-contains? html "data-sg-sse=\"/events\""))
226 (assert-true (string-contains? html "id=\"chat\"")))))
228;; ============================================================
229;; field helpers
230;; ============================================================
232(test-group "field helpers"
233 (test "text field"
234 (let ((html (sxml->xml (sg-text-field name: "username"))))
235 (assert-true (string-contains? html "type=\"text\""))
236 (assert-true (string-contains? html "name=\"username\""))))
238 (test "email field"
239 (let ((html (sxml->xml (sg-email-field name: "email"))))
240 (assert-true (string-contains? html "type=\"email\""))))
242 (test "password field"
243 (let ((html (sxml->xml (sg-password-field name: "pass"))))
244 (assert-true (string-contains? html "type=\"password\""))))
246 (test "hidden field"
247 (let ((html (sxml->xml (sg-hidden-field name: "token" value: "abc"))))
248 (assert-true (string-contains? html "type=\"hidden\""))
249 (assert-true (string-contains? html "value=\"abc\""))))
251 (test "textarea"
252 (let ((html (sxml->xml (sg-textarea-field name: "bio" value: "hello"))))
253 (assert-true (string-contains? html "<textarea"))
254 (assert-true (string-contains? html "name=\"bio\""))
255 (assert-true (string-contains? html "hello"))))
257 (test "select with string options"
258 (let ((html (sxml->xml (sg-select-field name: "color"
259 options: '("red" "green" "blue")))))
260 (assert-true (string-contains? html "<select"))
261 (assert-true (string-contains? html "value=\"red\""))
262 (assert-true (string-contains? html "value=\"blue\""))))
264 (test "select with pair options"
265 (let ((html (sxml->xml (sg-select-field name: "size"
266 options: '(("s" . "Small") ("m" . "Medium"))))))
267 (assert-true (string-contains? html "value=\"s\""))
268 (assert-true (string-contains? html "Small"))))
270 (test "select with selected value"
271 (let ((html (sxml->xml (sg-select-field name: "x"
272 options: '("a" "b")
273 value: "b"))))
274 (assert-true (string-contains? html "selected"))))
276 (test "checkbox unchecked"
277 (let ((html (sxml->xml (sg-checkbox-field name: "agree"))))
278 (assert-true (string-contains? html "type=\"checkbox\""))
279 (assert-false (string-contains? html "checked"))))
281 (test "checkbox checked"
282 (let ((html (sxml->xml (sg-checkbox-field name: "agree" checked: #t))))
283 (assert-true (string-contains? html "checked"))))
285 (test "submit button"
286 (let ((html (sxml->xml (sg-submit-button label: "Go"))))
287 (assert-true (string-contains? html "type=\"submit\""))
288 (assert-true (string-contains? html "Go")))))
290;; ============================================================
291;; field states
292;; ============================================================
294(test-group "field states"
295 (test "disabled text field"
296 (let ((html (sxml->xml (sg-text-field name: "x" disabled: #t))))
297 (assert-true (string-contains? html "disabled=\"disabled\""))))
299 (test "autofocus email field"
300 (let ((html (sxml->xml (sg-email-field name: "x" autofocus: #t))))
301 (assert-true (string-contains? html "autofocus=\"autofocus\""))))
303 (test "readonly password field"
304 (let ((html (sxml->xml (sg-password-field name: "x" readonly: #t))))
305 (assert-true (string-contains? html "readonly=\"readonly\""))))
307 (test "disabled textarea"
308 (let ((html (sxml->xml (sg-textarea-field name: "x" disabled: #t))))
309 (assert-true (string-contains? html "disabled=\"disabled\""))))
311 (test "disabled select"
312 (let ((html (sxml->xml (sg-select-field name: "x" options: '("a") disabled: #t))))
313 (assert-true (string-contains? html "disabled=\"disabled\""))))
315 (test "disabled checkbox"
316 (let ((html (sxml->xml (sg-checkbox-field name: "x" disabled: #t))))
317 (assert-true (string-contains? html "disabled=\"disabled\""))))
319 (test "disabled button"
320 (let ((html (sxml->xml (sg-button "X" action: "/x" disabled: #t))))
321 (assert-true (string-contains? html "disabled=\"disabled\""))))
323 (test "disabled submit button"
324 (let ((html (sxml->xml (sg-submit-button label: "Go" disabled: #t))))
325 (assert-true (string-contains? html "disabled=\"disabled\"")))))
327;; ============================================================
328;; label/input association
329;; ============================================================
331(test-group "label/input association"
332 (test "text field with label uses for/id"
333 (let ((html (sxml->xml (sg-text-field name: "user" label: "Username"))))
334 (assert-true (string-contains? html "<div>"))
335 (assert-true (string-contains? html "<label for=\"field-user\">Username</label>"))
336 (assert-true (string-contains? html "id=\"field-user\""))))
338 (test "text field with explicit id"
339 (let ((html (sxml->xml (sg-text-field name: "user" label: "Username" id: "my-id"))))
340 (assert-true (string-contains? html "<label for=\"my-id\">Username</label>"))
341 (assert-true (string-contains? html "id=\"my-id\""))))
343 (test "text field without label has no wrapper"
344 (let ((html (sxml->xml (sg-text-field name: "user"))))
345 (assert-false (string-contains? html "<div>"))
346 (assert-false (string-contains? html "<label"))))
348 (test "checkbox label comes after input"
349 (let ((html (sxml->xml (sg-checkbox-field name: "agree" label: "I agree"))))
350 (assert-true (string-contains? html "<div>"))
351 (let ((input-pos (string-find html "<input"))
352 (label-pos (string-find html "<label")))
353 (assert-true (< input-pos label-pos))))))
355;; ============================================================
356;; error feedback
357;; ============================================================
359(test-group "error feedback"
360 (test "text field with error"
361 (let ((html (sxml->xml (sg-text-field name: "user" label: "Username"
362 error: "Required"))))
363 (assert-true (string-contains? html "<span class=\"field-error\">Required</span>"))))
365 (test "text field with custom error class"
366 (let ((html (sxml->xml (sg-text-field name: "user" label: "Username"
367 error: "Bad" error-class: "err"))))
368 (assert-true (string-contains? html "<span class=\"err\">Bad</span>"))))
370 (test "error without label still wraps in div"
371 (let ((html (sxml->xml (sg-text-field name: "user" error: "Required"))))
372 (assert-true (string-contains? html "<div>"))
373 (assert-true (string-contains? html "<span class=\"field-error\">Required</span>"))
374 (assert-false (string-contains? html "<label"))))
376 (test "no error no label no wrapper"
377 (let ((html (sxml->xml (sg-text-field name: "user"))))
378 (assert-false (string-contains? html "<div>"))
379 (assert-false (string-contains? html "<span")))))
381;; ============================================================
382;; sigil-web-ui-head
383;; ============================================================
385(test-group "sigil-web-ui-head"
386 (test "generates script tags"
387 (let ((tags (sigil-web-ui-head)))
388 (assert-equal 2 (length tags))
389 (let ((html (string-join (map sxml->xml tags) "")))
390 (assert-true (string-contains? html "idiomorph"))
391 (assert-true (string-contains? html "sigil-web-ui.js")))))
393 (test "custom URLs"
394 (let ((tags (sigil-web-ui-head idiomorph-url: "/my-idiomorph.js"
395 script-url: "/my-sigil.js")))
396 (let ((html (string-join (map sxml->xml tags) "")))
397 (assert-true (string-contains? html "/my-idiomorph.js"))
398 (assert-true (string-contains? html "/my-sigil.js"))))))
400;; ============================================================
401;; sg-flash-message
402;; ============================================================
404(test-group "sg-flash-message"
405 (test "basic flash with type"
406 (let ((html (sxml->xml (sg-flash-message type: 'success message: "Saved!"))))
407 (assert-true (string-contains? html "role=\"alert\""))
408 (assert-true (string-contains? html "sg-flash sg-flash-success"))
409 (assert-true (string-contains? html "Saved!"))))
411 (test "default type is info"
412 (let ((html (sxml->xml (sg-flash-message message: "Hello"))))
413 (assert-true (string-contains? html "sg-flash-info"))))
415 (test "with remove-after"
416 (let ((html (sxml->xml (sg-flash-message type: 'warning message: "Watch out"
417 remove-after: 3000))))
418 (assert-true (string-contains? html "data-sg-remove-after=\"3000\""))))
420 (test "without remove-after"
421 (let ((html (sxml->xml (sg-flash-message type: 'error message: "Oops"))))
422 (assert-false (string-contains? html "data-sg-remove-after"))))
424 (test "with custom class"
425 (let ((html (sxml->xml (sg-flash-message type: 'info message: "Note"
426 class: "my-flash"))))
427 (assert-true (string-contains? html "sg-flash sg-flash-info my-flash"))))
429 (test "with id"
430 (let ((html (sxml->xml (sg-flash-message type: 'success message: "OK"
431 id: "flash-1"))))
432 (assert-true (string-contains? html "id=\"flash-1\""))))
434 (test "SXML list message"
435 (let ((html (sxml->xml (sg-flash-message type: 'info
436 message: '((strong "Bold") " text")))))
437 (assert-true (string-contains? html "<strong>Bold</strong>"))
438 (assert-true (string-contains? html " text")))))
440;; ============================================================
441;; sse-flash
442;; ============================================================
444(test-group "sse-flash"
445 (test "generates SSE morph event with append mode"
446 (let ((event (sse-flash type: 'success message: "Done" remove-after: 3000)))
447 (assert-true (string-contains? event "event: sigil:morph"))
448 (assert-true (string-contains? event "data: target #sg-flash-container"))
449 (assert-true (string-contains? event "data: mode append"))
450 (assert-true (string-contains? event "sg-flash-success"))
451 (assert-true (string-contains? event "Done"))))
453 (test "custom target"
454 (let ((event (sse-flash type: 'info message: "Hi" target: "#my-flash")))
455 (assert-true (string-contains? event "data: target #my-flash")))))
457;; ============================================================
458;; sg-loading-indicator
459;; ============================================================
461(test-group "sg-loading-indicator"
462 (test "inactive by default"
463 (let ((html (sxml->xml (sg-loading-indicator))))
464 (assert-true (string-contains? html "class=\"sg-loading\""))
465 (assert-true (string-contains? html "aria-hidden=\"true\""))
466 (assert-false (string-contains? html "active"))))
468 (test "active state"
469 (let ((html (sxml->xml (sg-loading-indicator active: #t))))
470 (assert-true (string-contains? html "sg-loading active"))
471 (assert-true (string-contains? html "aria-hidden=\"false\""))))
473 (test "with custom class"
474 (let ((html (sxml->xml (sg-loading-indicator class: "spinner"))))
475 (assert-true (string-contains? html "sg-loading spinner"))))
477 (test "with id"
478 (let ((html (sxml->xml (sg-loading-indicator id: "loader"))))
479 (assert-true (string-contains? html "id=\"loader\"")))))
481;; ============================================================
482;; sg-modal
483;; ============================================================
485(test-group "sg-modal"
486 (test "basic dialog element"
487 (let ((html (sxml->xml (sg-modal '((p "Content")) id: "my-modal"))))
488 (assert-true (string-contains? html "<dialog"))
489 (assert-true (string-contains? html "id=\"my-modal\""))
490 (assert-true (string-contains? html "<p>Content</p>"))))
492 (test "with title"
493 (let ((html (sxml->xml (sg-modal '((p "Body")) id: "m" title: "My Title"))))
494 (assert-true (string-contains? html "<h2>My Title</h2>"))))
496 (test "without title"
497 (let ((html (sxml->xml (sg-modal '((p "Body")) id: "m"))))
498 (assert-false (string-contains? html "<h2>"))))
500 (test "with class"
501 (let ((html (sxml->xml (sg-modal '() id: "m" class: "wide"))))
502 (assert-true (string-contains? html "class=\"wide\"")))))
504;; ============================================================
505;; sg-modal-trigger
506;; ============================================================
508(test-group "sg-modal-trigger"
509 (test "button with data-sg-modal attribute"
510 (let ((html (sxml->xml (sg-modal-trigger "Open" target: "#my-modal"))))
511 (assert-true (string-contains? html "<button"))
512 (assert-true (string-contains? html "type=\"button\""))
513 (assert-true (string-contains? html "data-sg-modal=\"#my-modal\""))
514 (assert-true (string-contains? html "Open"))))
516 (test "with class and id"
517 (let ((html (sxml->xml (sg-modal-trigger "Go" target: "#m"
518 class: "btn" id: "trigger"))))
519 (assert-true (string-contains? html "class=\"btn\""))
520 (assert-true (string-contains? html "id=\"trigger\"")))))
522;; ============================================================
523;; sg-modal-close
524;; ============================================================
526(test-group "sg-modal-close"
527 (test "button with data-sg-modal-close"
528 (let ((html (sxml->xml (sg-modal-close "Cancel"))))
529 (assert-true (string-contains? html "<button"))
530 (assert-true (string-contains? html "data-sg-modal-close"))
531 (assert-true (string-contains? html "Cancel"))))
533 (test "with class"
534 (let ((html (sxml->xml (sg-modal-close "Close" class: "btn-secondary"))))
535 (assert-true (string-contains? html "class=\"btn-secondary\"")))))
537;; ============================================================
538;; sg-data-table
539;; ============================================================
541(test-group "sg-data-table"
542 (test "empty table shows message"
543 (let ((html (sxml->xml (sg-data-table columns: '((name "Name") (email "Email"))
544 rows: '()))))
545 (assert-true (string-contains? html "<table"))
546 (assert-true (string-contains? html "<th>Name</th>"))
547 (assert-true (string-contains? html "<th>Email</th>"))
548 (assert-true (string-contains? html "No data available."))))
550 (test "custom empty message"
551 (let ((html (sxml->xml (sg-data-table columns: '((x "X"))
552 rows: '()
553 empty-message: "Nothing here"))))
554 (assert-true (string-contains? html "Nothing here"))))
556 (test "renders alist rows"
557 (let ((html (sxml->xml (sg-data-table
558 columns: '((name "Name") (age "Age"))
559 rows: '(((name . "Alice") (age . 30))
560 ((name . "Bob") (age . 25)))))))
561 (assert-true (string-contains? html "<th>Name</th>"))
562 (assert-true (string-contains? html "<th>Age</th>"))
563 (assert-true (string-contains? html "<td>Alice</td>"))
564 (assert-true (string-contains? html "<td>30</td>"))
565 (assert-true (string-contains? html "<td>Bob</td>"))
566 (assert-true (string-contains? html "<td>25</td>"))))
568 (test "renders dict rows"
569 (let ((html (sxml->xml (sg-data-table
570 columns: '((name "Name"))
571 rows: (list (dict name: "Carol"))))))
572 (assert-true (string-contains? html "<td>Carol</td>"))))
574 (test "with row actions"
575 (let ((html (sxml->xml (sg-data-table
576 columns: '((name "Name"))
577 rows: '(((name . "Alice") (id . "1")))
578 row-actions: (list
579 (sg-table-action "Edit"
580 action: "/users/{id}/edit")
581 (sg-table-action "Delete"
582 action: "/users/{id}"
583 method: "delete"
584 confirm: "Sure?"))))))
585 (assert-true (string-contains? html "<th>Actions</th>"))
586 (assert-true (string-contains? html "data-sg-action=\"/users/1/edit\""))
587 (assert-true (string-contains? html "data-sg-action=\"/users/1\""))
588 (assert-true (string-contains? html "data-sg-confirm=\"Sure?\""))
589 (assert-true (string-contains? html "Edit"))
590 (assert-true (string-contains? html "Delete"))))
592 (test "with class and id"
593 (let ((html (sxml->xml (sg-data-table columns: '((x "X"))
594 rows: '(((x . "1")))
595 class: "striped" id: "tbl"))))
596 (assert-true (string-contains? html "class=\"striped\""))
597 (assert-true (string-contains? html "id=\"tbl\"")))))
599;; ============================================================
600;; sg-paginator
601;; ============================================================
603(test-group "sg-paginator"
604 (test "single page - both prev/next disabled"
605 (let ((html (sxml->xml (sg-paginator current-page: 1 total-pages: 1
606 base-url: "/items"))))
607 (assert-true (string-contains? html "<nav"))
608 (assert-true (string-contains? html "sg-paginator"))
609 (assert-true (string-contains? html "class=\"disabled\">Previous"))
610 (assert-true (string-contains? html "class=\"disabled\">Next"))
611 (assert-true (string-contains? html "class=\"current\">1"))))
613 (test "first page - prev disabled, next enabled"
614 (let ((html (sxml->xml (sg-paginator current-page: 1 total-pages: 5
615 base-url: "/items"))))
616 (assert-true (string-contains? html "class=\"disabled\">Previous"))
617 (assert-true (string-contains? html "page=2"))
618 (assert-true (string-contains? html "class=\"current\">1"))))
620 (test "last page - next disabled, prev enabled"
621 (let ((html (sxml->xml (sg-paginator current-page: 5 total-pages: 5
622 base-url: "/items"))))
623 (assert-true (string-contains? html "class=\"disabled\">Next"))
624 (assert-true (string-contains? html "page=4"))))
626 (test "middle page - both prev/next enabled"
627 (let ((html (sxml->xml (sg-paginator current-page: 3 total-pages: 5
628 base-url: "/items"))))
629 (assert-true (string-contains? html "page=2")) ; prev
630 (assert-true (string-contains? html "page=4")) ; next
631 (assert-true (string-contains? html "class=\"current\">3"))))
633 (test "with extra params"
634 (let ((html (sxml->xml (sg-paginator current-page: 1 total-pages: 3
635 base-url: "/items"
636 params: '((sort . "name"))))))
637 (assert-true (string-contains? html "sort=name"))
638 (assert-true (string-contains? html "page="))))
640 (test "ellipsis for large page count"
641 (let ((html (sxml->xml (sg-paginator current-page: 5 total-pages: 20
642 base-url: "/items"))))
643 (assert-true (string-contains? html "..."))
644 (assert-true (string-contains? html "class=\"current\">5"))))
646 (test "with target"
647 (let ((html (sxml->xml (sg-paginator current-page: 1 total-pages: 3
648 base-url: "/items"
649 target: "#list"))))
650 (assert-true (string-contains? html "data-sg-target=\"#list\""))))
652 (test "with class and id"
653 (let ((html (sxml->xml (sg-paginator current-page: 1 total-pages: 3
654 base-url: "/items"
655 class: "my-pager" id: "pager"))))
656 (assert-true (string-contains? html "sg-paginator my-pager"))
657 (assert-true (string-contains? html "id=\"pager\"")))))
659(run-tests)