A tiny web framework for Gleam targeting all JavaScript runtimes
0

Configure Feed

Select the types of activity you want to include in your feed.

tests!

+326
+326
test/smol_test.gleam
··· 1 1 import gleam/dynamic.{type Dynamic} 2 + import gleam/dynamic/decode 2 3 import gleam/http.{Get, Head, Http, Options, Post, Put} 3 4 import gleam/http/request 4 5 import gleam/http/response 5 6 import gleam/javascript/promise.{type Promise} 7 + import gleam/json 6 8 import gleam/list 7 9 import gleam/option 8 10 import gleam/result ··· 62 64 promise.resolve(Nil) 63 65 } 64 66 67 + pub fn read_json_decodes_body_test() -> Promise(Nil) { 68 + let request = request_with_body([<<"{\"one\":1,\"two\":2}">>]) 69 + 70 + use response <- promise.await( 71 + smol.read_json( 72 + request, 73 + using: two_ints_decoder(), 74 + up_to: 32, 75 + then: fn(pair) { 76 + assert pair == #(1, 2) 77 + smol.send_string("ok") 78 + }, 79 + ), 80 + ) 81 + assert response.status == 200 82 + 83 + promise.resolve(Nil) 84 + } 85 + 86 + pub fn read_json_rejects_too_large_body_test() -> Promise(Nil) { 87 + let request = request_with_body([<<"{\"one\":1,\"two\":2}">>]) 88 + 89 + use response <- promise.await( 90 + smol.read_json(request, using: two_ints_decoder(), up_to: 1, then: fn(_) { 91 + smol.send_string("unexpected") 92 + }), 93 + ) 94 + assert response.status == 413 95 + 96 + use text <- promise.await(stream_text(response.body)) 97 + assert text == "Payload Too Large" 98 + 99 + promise.resolve(Nil) 100 + } 101 + 102 + pub fn read_json_rejects_invalid_json_test() -> Promise(Nil) { 103 + let request = request_with_body([<<"{\"one\":">>]) 104 + 105 + use response <- promise.await( 106 + smol.read_json(request, using: two_ints_decoder(), up_to: 32, then: fn(_) { 107 + smol.send_string("unexpected") 108 + }), 109 + ) 110 + assert response.status == 422 111 + 112 + use text <- promise.await(stream_text(response.body)) 113 + assert text == "Unprocessable Entity" 114 + 115 + promise.resolve(Nil) 116 + } 117 + 118 + pub fn read_form_reads_urlencoded_fields_test() -> Promise(Nil) { 119 + let request = request_with_body([<<"one=1&two=2">>]) 120 + 121 + use response <- promise.await( 122 + smol.read_form(request, up_to: 16, then: fn(fields) { 123 + assert fields == [#("one", "1"), #("two", "2")] 124 + smol.send_string("ok") 125 + }), 126 + ) 127 + assert response.status == 200 128 + 129 + promise.resolve(Nil) 130 + } 131 + 132 + pub fn read_form_rejects_too_large_body_test() -> Promise(Nil) { 133 + let request = request_with_body([<<"one=1">>]) 134 + 135 + use response <- promise.await( 136 + smol.read_form(request, up_to: 4, then: fn(_fields) { 137 + smol.send_string("unexpected") 138 + }), 139 + ) 140 + assert response.status == 413 141 + 142 + use text <- promise.await(stream_text(response.body)) 143 + assert text == "Payload Too Large" 144 + 145 + promise.resolve(Nil) 146 + } 147 + 65 148 pub fn read_multipart_reads_fields_and_uploads_test() -> Promise(Nil) { 66 149 let request = multipart_request([<<multipart_body():utf8>>]) 67 150 ··· 188 271 189 272 use text <- promise.await(stream_text(response.body)) 190 273 assert text == "hello" 274 + 275 + promise.resolve(Nil) 276 + } 277 + 278 + pub fn handle_head_passes_through_get_test() -> Promise(Nil) { 279 + let request = request_with_method_headers_body(Get, [], []) 280 + 281 + use response <- promise.await( 282 + smol.handle_head(request, then: fn(request) { 283 + assert request.method == Get 284 + assert request.get_header(request, "x-original-method") == Error(Nil) 285 + smol.send_string("hello") 286 + }), 287 + ) 288 + assert response.status == 200 289 + 290 + use text <- promise.await(stream_text(response.body)) 291 + assert text == "hello" 292 + 293 + promise.resolve(Nil) 294 + } 295 + 296 + pub fn handle_head_passes_through_post_test() -> Promise(Nil) { 297 + let request = request_with_method_headers_body(Post, [], []) 298 + 299 + use response <- promise.await( 300 + smol.handle_head(request, then: fn(request) { 301 + assert request.method == Post 302 + assert request.get_header(request, "x-original-method") == Error(Nil) 303 + smol.require_method(request, require: Get, then: fn() { 304 + smol.send_string("unexpected") 305 + }) 306 + }), 307 + ) 308 + assert response.status == 405 309 + assert_header(response, "allow", "GET") 191 310 192 311 promise.resolve(Nil) 193 312 } ··· 430 549 promise.resolve(Nil) 431 550 } 432 551 552 + pub fn require_method_allows_matching_method_test() -> Promise(Nil) { 553 + let request = request_with_method_headers_body(Get, [], []) 554 + 555 + use response <- promise.await( 556 + smol.require_method(request, require: Get, then: fn() { 557 + smol.send_string("ok") 558 + }), 559 + ) 560 + assert response.status == 200 561 + 562 + promise.resolve(Nil) 563 + } 564 + 565 + pub fn require_method_rejects_other_method_test() -> Promise(Nil) { 566 + let request = request_with_method_headers_body(Post, [], []) 567 + 568 + use response <- promise.await( 569 + smol.require_method(request, require: Get, then: fn() { 570 + smol.send_string("unexpected") 571 + }), 572 + ) 573 + assert response.status == 405 574 + assert_header(response, "allow", "GET") 575 + 576 + use text <- promise.await(stream_text(response.body)) 577 + assert text == "Method Not Allowed" 578 + 579 + promise.resolve(Nil) 580 + } 581 + 582 + pub fn require_content_type_allows_exact_match_test() -> Promise(Nil) { 583 + let request = 584 + request_with_method_headers_body( 585 + Post, 586 + [#("content-type", "text/plain")], 587 + [], 588 + ) 589 + 590 + use response <- promise.await( 591 + smol.require_content_type(request, accept: ["text/plain"], then: fn() { 592 + smol.send_string("ok") 593 + }), 594 + ) 595 + assert response.status == 200 596 + 597 + promise.resolve(Nil) 598 + } 599 + 600 + pub fn require_content_type_allows_charset_test() -> Promise(Nil) { 601 + let request = 602 + request_with_method_headers_body( 603 + Post, 604 + [#("content-type", "text/plain; charset=utf-8")], 605 + [], 606 + ) 607 + 608 + use response <- promise.await( 609 + smol.require_content_type(request, accept: ["text/plain"], then: fn() { 610 + smol.send_string("ok") 611 + }), 612 + ) 613 + assert response.status == 200 614 + 615 + promise.resolve(Nil) 616 + } 617 + 618 + pub fn require_content_type_rejects_missing_header_test() -> Promise(Nil) { 619 + let request = request_with_method_headers_body(Post, [], []) 620 + 621 + use response <- promise.await( 622 + smol.require_content_type(request, accept: ["text/plain"], then: fn() { 623 + smol.send_string("unexpected") 624 + }), 625 + ) 626 + assert response.status == 415 627 + assert_header(response, "accept", "text/plain") 628 + 629 + use text <- promise.await(stream_text(response.body)) 630 + assert text == "Unsupported Media Type" 631 + 632 + promise.resolve(Nil) 633 + } 634 + 635 + pub fn require_content_type_rejects_other_type_test() -> Promise(Nil) { 636 + let request = 637 + request_with_method_headers_body( 638 + Post, 639 + [#("content-type", "text/plain")], 640 + [], 641 + ) 642 + 643 + use response <- promise.await( 644 + smol.require_content_type(request, accept: ["text/html"], then: fn() { 645 + smol.send_string("unexpected") 646 + }), 647 + ) 648 + assert response.status == 415 649 + assert_header(response, "accept", "text/html") 650 + 651 + promise.resolve(Nil) 652 + } 653 + 433 654 pub fn csrf_known_header_protection_allows_safe_methods_test() -> Promise(Nil) { 434 655 let request = request_with_method_headers_body(Get, [], []) 435 656 ··· 580 801 promise.resolve(Nil) 581 802 } 582 803 804 + pub fn send_html_sets_content_type_and_body_test() -> Promise(Nil) { 805 + use response <- promise.await(smol.send_html("<h1>Hello</h1>")) 806 + 807 + assert response.status == 200 808 + assert_header(response, "content-type", "text/html; charset=utf-8") 809 + 810 + use text <- promise.await(stream_text(response.body)) 811 + assert text == "<h1>Hello</h1>" 812 + 813 + promise.resolve(Nil) 814 + } 815 + 816 + pub fn send_json_sets_content_type_and_body_test() -> Promise(Nil) { 817 + use response <- promise.await( 818 + smol.send_json( 819 + json.object([ 820 + #("one", json.int(1)), 821 + #("two", json.int(2)), 822 + ]), 823 + ), 824 + ) 825 + 826 + assert response.status == 200 827 + assert_header(response, "content-type", "application/json; charset=utf-8") 828 + 829 + use text <- promise.await(stream_text(response.body)) 830 + assert text == "{\"one\":1,\"two\":2}" 831 + 832 + promise.resolve(Nil) 833 + } 834 + 835 + pub fn send_status_uses_standard_status_text_test() -> Promise(Nil) { 836 + use response <- promise.await(smol.send_status(404)) 837 + 838 + assert response.status == 404 839 + assert_header(response, "content-type", "text/plain; charset=utf-8") 840 + 841 + use text <- promise.await(stream_text(response.body)) 842 + assert text == "Not Found" 843 + 844 + promise.resolve(Nil) 845 + } 846 + 847 + pub fn redirect_sets_see_other_location_test() -> Promise(Nil) { 848 + use response <- promise.await(smol.redirect(to: "https://example.com/wibble")) 849 + 850 + assert response.status == 303 851 + assert_header(response, "location", "https://example.com/wibble") 852 + 853 + use text <- promise.await(stream_text(response.body)) 854 + assert text == "https://example.com/wibble" 855 + 856 + promise.resolve(Nil) 857 + } 858 + 859 + pub fn moved_permanently_sets_location_test() -> Promise(Nil) { 860 + use response <- promise.await(smol.moved_permanently( 861 + to: "https://example.com/wobble", 862 + )) 863 + 864 + assert response.status == 308 865 + assert_header(response, "location", "https://example.com/wobble") 866 + 867 + use text <- promise.await(stream_text(response.body)) 868 + assert text == "https://example.com/wobble" 869 + 870 + promise.resolve(Nil) 871 + } 872 + 873 + pub fn with_status_replaces_status_test() -> Promise(Nil) { 874 + use response <- promise.await( 875 + smol.send_string("created") 876 + |> smol.with_status(201), 877 + ) 878 + 879 + assert response.status == 201 880 + 881 + use text <- promise.await(stream_text(response.body)) 882 + assert text == "created" 883 + 884 + promise.resolve(Nil) 885 + } 886 + 887 + pub fn with_extra_headers_replaces_normal_headers_test() -> Promise(Nil) { 888 + use response <- promise.await( 889 + smol.send_string("ok") 890 + |> smol.with_extra_headers([ 891 + #("accept", "application/json"), 892 + #("accept", "text/plain"), 893 + #("content-type", "text/html"), 894 + ]), 895 + ) 896 + 897 + assert_header(response, "accept", "text/plain") 898 + assert_header(response, "content-type", "text/html") 899 + 900 + promise.resolve(Nil) 901 + } 902 + 583 903 pub fn as_file_download_sets_content_disposition_test() -> Promise(Nil) { 584 904 use response <- promise.await( 585 905 smol.send_string("{}") ··· 695 1015 696 1016 fn send_status_handler(status) { 697 1017 smol.adapt(fn(_request) { smol.send_status(status) }) 1018 + } 1019 + 1020 + fn two_ints_decoder() { 1021 + use one <- decode.field("one", decode.int) 1022 + use two <- decode.field("two", decode.int) 1023 + decode.success(#(one, two)) 698 1024 } 699 1025 700 1026 fn assert_null_body_response(response, expected_status) {