what-core 1.7.0

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 form_w_validate_injects_hidden_field() {
    let proj = TestProject::new();
    proj.add_page(
        "form.html",
        r#"<form w-validate action="/w-action/users?w-redirect=/form">
        <input type="text" name="email" w-required w-type="email">
        <input type="submit" value="Submit">
    </form>"#,
    );
    let (_dir, state) = proj.build_state();
    let router = create_router(state);

    let resp = get(&router, "/form").await;
    assert_eq!(resp.status, StatusCode::OK);
    resp.assert_contains(r#"name="w-rules""#);
    resp.assert_contains(r#"type="hidden""#);
}

#[tokio::test]
async fn form_without_w_validate_no_hidden_field() {
    let proj = TestProject::new();
    proj.add_page(
        "form.html",
        r#"<form action="/w-action/users?w-redirect=/form">
        <input type="text" name="email" w-required>
        <input type="submit" value="Submit">
    </form>"#,
    );
    let (_dir, state) = proj.build_state();
    let router = create_router(state);

    let resp = get(&router, "/form").await;
    assert_eq!(resp.status, StatusCode::OK);
    resp.assert_not_contains(r#"name="w-rules""#);
}

#[tokio::test]
async fn validation_redirect_on_failure() {
    let proj = TestProject::new();
    // Create a form with required field validation
    proj.add_page(
        "form.html",
        r##"<form w-validate action="/w-action/users?w-redirect=/success">
        <input type="text" name="email" w-required w-type="email">
        <input type="submit" value="Submit">
    </form>
    <p>#errors.email|default:"no-error"#</p>"##,
    );
    proj.add_page("success.html", "<h1>Success</h1>");
    let (_dir, state) = proj.build_state();
    let router = create_router(state);

    // First, render the form to get the w-rules token
    let form_resp = get(&router, "/form").await;
    let body = &form_resp.body;

    // Extract the w-rules token from the hidden field
    let token_start =
        body.find(r#"name="w-rules" value=""#).unwrap() + r#"name="w-rules" value=""#.len();
    let token_end = body[token_start..].find('"').unwrap() + token_start;
    let token = &body[token_start..token_end];

    // Submit with empty email (should fail validation)
    let form_data = format!("email=&w-rules={}", token);
    let resp = post_form_with_headers(
        &router,
        "/w-action/users?w-redirect=/success",
        &form_data,
        vec![("referer", "/form")],
    )
    .await;

    // Should redirect back to form (not to success)
    assert_eq!(resp.status, StatusCode::SEE_OTHER);
    assert_eq!(resp.location(), Some("/form"));
}

#[tokio::test]
async fn validation_passes_on_valid_data() {
    let proj = TestProject::new();
    proj.add_page(
        "form.html",
        r#"<form w-validate action="/w-action/users?w-redirect=/success">
        <input type="text" name="email" w-required w-type="email">
        <input type="submit">
    </form>"#,
    );
    proj.add_page("success.html", "<h1>Success</h1>");
    let (_dir, state) = proj.build_state();
    let router = create_router(state);

    // Get form to extract token
    let form_resp = get(&router, "/form").await;
    let body = &form_resp.body;
    let token_start =
        body.find(r#"name="w-rules" value=""#).unwrap() + r#"name="w-rules" value=""#.len();
    let token_end = body[token_start..].find('"').unwrap() + token_start;
    let token = &body[token_start..token_end];

    // Submit with valid email
    let form_data = format!("email=test@example.com&w-rules={}", token);
    let resp = post_form(&router, "/w-action/users?w-redirect=/success", &form_data).await;

    // Should redirect to success (validation passed)
    assert_eq!(resp.status, StatusCode::SEE_OTHER);
    assert_eq!(resp.location(), Some("/success"));
}

#[tokio::test]
async fn validation_errors_in_flash() {
    let proj = TestProject::new();
    proj.add_page(
        "form.html",
        r##"<form w-validate action="/w-action/users?w-redirect=/success">
        <input type="text" name="name" w-required>
        <input type="submit">
    </form>
    <p>error: #errors.name|default:"none"#</p>
    <p>has: #has_errors#</p>"##,
    );
    let (_dir, state) = proj.build_state();
    let router = create_router(state);

    // Get token
    let form_resp = get(&router, "/form").await;
    let body = &form_resp.body;
    let token_start =
        body.find(r#"name="w-rules" value=""#).unwrap() + r#"name="w-rules" value=""#.len();
    let token_end = body[token_start..].find('"').unwrap() + token_start;
    let token = &body[token_start..token_end];

    // Submit empty (fails validation)
    let form_data = format!("name=&w-rules={}", token);
    let resp = post_form_with_headers(
        &router,
        "/w-action/users?w-redirect=/success",
        &form_data,
        vec![("referer", "/form")],
    )
    .await;
    let cookie = resp.set_cookie().expect("should set session cookie");

    // Load form again — should see error
    let resp = get_with_headers(&router, "/form", vec![("cookie", cookie)]).await;
    resp.assert_contains("name is required");
    resp.assert_contains("has: true");
}