AtlatestRepositorysigil-web
1
(import (sigil test)2
(sigil string)3
(sigil sxml)4
(sigil web ui)5
(sigil http response))7
;; ============================================================8
;; sse-morph9
;; ============================================================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-remove37
;; ============================================================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-class48
;; ============================================================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-eval69
;; ============================================================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-redirect88
;; ============================================================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-reload98
;; ============================================================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-response117
;; ============================================================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-redirect139
;; ============================================================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-batch152
;; ============================================================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-button167
;; ============================================================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-link191
;; ============================================================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-form206
;; ============================================================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-sse220
;; ============================================================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 helpers230
;; ============================================================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 states292
;; ============================================================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 association329
;; ============================================================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 feedback357
;; ============================================================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-head383
;; ============================================================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-message402
;; ============================================================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: 'info436
message: '((strong "Bold") " text")))))437
(assert-true (string-contains? html "<strong>Bold</strong>"))438
(assert-true (string-contains? html " text")))))440
;; ============================================================441
;; sse-flash442
;; ============================================================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-indicator459
;; ============================================================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-modal483
;; ============================================================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-trigger506
;; ============================================================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-close524
;; ============================================================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-table539
;; ============================================================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-table558
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-table570
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-table576
columns: '((name "Name"))577
rows: '(((name . "Alice") (id . "1")))578
row-actions: (list579
(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-paginator601
;; ============================================================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: 1606
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: 5615
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: 5622
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: 5628
base-url: "/items"))))629
(assert-true (string-contains? html "page=2")) ; prev630
(assert-true (string-contains? html "page=4")) ; next631
(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: 3635
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: 20642
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: 3648
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: 3654
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)