what-core 1.7.5

Core framework for What - an HTML-first web framework powered by Rust
Documentation
mod common;

use axum::http::StatusCode;
use common::*;
use what_core::server::create_router;

#[tokio::test]
async fn loop_with_paginate_shows_first_page() {
    let proj = TestProject::new();
    proj.add_data_file("data/store.json", r#"{"collections":{"items":[{"name":"A"},{"name":"B"},{"name":"C"},{"name":"D"},{"name":"E"}]},"values":{}}"#);
    proj.add_page(
        "index.html",
        r##"<loop data="#items#" as="item" paginate="2" page="1"><p>#item.name#</p></loop>"##,
    );
    let (_dir, state) = proj.build_state();
    let router = create_router(state);

    let resp = get(&router, "/").await;
    assert_eq!(resp.status, StatusCode::OK);
    resp.assert_contains("<p>A</p>");
    resp.assert_contains("<p>B</p>");
    resp.assert_not_contains("<p>C</p>");
}

#[tokio::test]
async fn loop_with_paginate_shows_second_page() {
    let proj = TestProject::new();
    proj.add_data_file("data/store.json", r#"{"collections":{"items":[{"name":"A"},{"name":"B"},{"name":"C"},{"name":"D"},{"name":"E"}]},"values":{}}"#);
    proj.add_page("index.html", r##"<loop data="#items#" as="item" paginate="2" page="#query.page|1#"><p>#item.name#</p></loop>"##);
    let (_dir, state) = proj.build_state();
    let router = create_router(state);

    let resp = get(&router, "/?page=2").await;
    assert_eq!(resp.status, StatusCode::OK);
    resp.assert_contains("<p>C</p>");
    resp.assert_contains("<p>D</p>");
    resp.assert_not_contains("<p>A</p>");
    resp.assert_not_contains("<p>E</p>");
}

#[tokio::test]
async fn loop_with_paginate_last_page_partial() {
    let proj = TestProject::new();
    proj.add_data_file("data/store.json", r#"{"collections":{"items":[{"name":"A"},{"name":"B"},{"name":"C"},{"name":"D"},{"name":"E"}]},"values":{}}"#);
    proj.add_page("index.html", r##"<loop data="#items#" as="item" paginate="2" page="#query.page|1#"><p>#item.name#</p></loop>"##);
    let (_dir, state) = proj.build_state();
    let router = create_router(state);

    let resp = get(&router, "/?page=3").await;
    assert_eq!(resp.status, StatusCode::OK);
    resp.assert_contains("<p>E</p>");
    resp.assert_not_contains("<p>D</p>");
}

#[tokio::test]
async fn loop_pagination_exposes_context_vars() {
    let proj = TestProject::new();
    proj.add_data_file("data/store.json", r#"{"collections":{"items":[{"name":"A"},{"name":"B"},{"name":"C"},{"name":"D"},{"name":"E"}]},"values":{}}"#);
    proj.add_page("index.html", r##"<loop data="#items#" as="item" paginate="2" page="2"><span>total:#loop_total# pages:#loop_pages# page:#loop_page#</span></loop>"##);
    let (_dir, state) = proj.build_state();
    let router = create_router(state);

    let resp = get(&router, "/").await;
    assert_eq!(resp.status, StatusCode::OK);
    resp.assert_contains("total:5");
    resp.assert_contains("pages:3");
    resp.assert_contains("page:2");
}

#[tokio::test]
async fn what_pagination_component_renders() {
    let proj = TestProject::new();
    proj.add_page(
        "index.html",
        r#"<what-pagination total="50" per-page="10" current="3" base-url="/blog"/>"#,
    );
    let (_dir, state) = proj.build_state();
    let router = create_router(state);

    let resp = get(&router, "/").await;
    assert_eq!(resp.status, StatusCode::OK);
    resp.assert_contains("what-pagination");
    resp.assert_contains("aria-current=\"page\""); // Active page
    resp.assert_contains(">3<"); // Current page number
    resp.assert_contains("/blog?page=2"); // Prev link
    resp.assert_contains("/blog?page=4"); // Next link
}

#[tokio::test]
async fn what_pagination_hidden_when_one_page() {
    let proj = TestProject::new();
    proj.add_page(
        "index.html",
        r#"<what-pagination total="5" per-page="10" current="1" base-url="/"/>"#,
    );
    let (_dir, state) = proj.build_state();
    let router = create_router(state);

    let resp = get(&router, "/").await;
    assert_eq!(resp.status, StatusCode::OK);
    resp.assert_not_contains("what-pagination");
}

#[tokio::test]
async fn what_pagination_prev_disabled_on_first_page() {
    let proj = TestProject::new();
    proj.add_page(
        "index.html",
        r#"<what-pagination total="30" per-page="10" current="1" base-url="/items"/>"#,
    );
    let (_dir, state) = proj.build_state();
    let router = create_router(state);

    let resp = get(&router, "/").await;
    assert_eq!(resp.status, StatusCode::OK);
    resp.assert_contains("what-pagination-disabled");
    // Should have next but disabled prev
    resp.assert_contains("/items?page=2");
}

#[tokio::test]
async fn what_pagination_next_disabled_on_last_page() {
    let proj = TestProject::new();
    proj.add_page(
        "index.html",
        r#"<what-pagination total="30" per-page="10" current="3" base-url="/items"/>"#,
    );
    let (_dir, state) = proj.build_state();
    let router = create_router(state);

    let resp = get(&router, "/").await;
    assert_eq!(resp.status, StatusCode::OK);
    // Next should be disabled, prev should work
    resp.assert_contains("/items?page=2"); // Prev link
}

#[tokio::test]
async fn what_pagination_ellipsis_for_many_pages() {
    let proj = TestProject::new();
    proj.add_page(
        "index.html",
        r#"<what-pagination total="200" per-page="10" current="10" base-url="/all"/>"#,
    );
    let (_dir, state) = proj.build_state();
    let router = create_router(state);

    let resp = get(&router, "/").await;
    assert_eq!(resp.status, StatusCode::OK);
    resp.assert_contains("what-pagination-ellipsis"); // Should have ellipsis
    resp.assert_contains(">1<"); // First page always shown
    resp.assert_contains(">20<"); // Last page always shown
}