makeover-webview 0.111.0

The webview renderer for makeover-layout. Emits CSS, and is the one renderer that needs no palette: var() is the late binding, so resolution stays with the browser. With the build feature, writes a consumer's generated frontend files and checks the hand-written ones against them.
Documentation
use super::*;

#[test]
fn every_escaped_sink_is_covered_by_the_one_escaper() {
    assert_eq!(escape("&<>\"'"), "&amp;&lt;&gt;&quot;&#39;");
    // The character `textContent` serialization leaves alone, which is why
    // the app needs two escapers and this needs one.
    assert!(escape("\"").contains("&quot;"));
}

/// The streaming escaper is the one the emitters call and [`escape`] is a
/// buffer around it, so the two cannot be allowed to drift. It copies in
/// runs between the encoded characters, which is where a multi-byte
/// character would break it if the scan were not restricted to ASCII.
#[test]
fn the_streaming_escaper_appends_what_the_returning_one_returns() {
    for text in [
        "",
        "plain",
        "&<>\"'",
        "&&&",
        "a & b",
        "trailing&",
        "&leading",
        "é世 & <b>naïve</b> \u{1f600}",
    ] {
        let mut out = String::from("kept: ");
        escape_into(text, &mut out);
        assert_eq!(out, format!("kept: {}", escape(text)), "{text:?}");
    }
}

#[test]
fn the_editor_rules_gate_on_the_attribute_and_on_a_binding() {
    let css = editor_rules(&Emit::default());
    // Behind the attribute, which is the reason the mark is an attribute:
    // a class-keyed gate would be prefixed away from the enhancement that
    // selects on it.
    for line in css.lines().filter(|line| line.contains('{')) {
        assert!(line.contains("[data-format=\"markdown\"]"), "{line}");
    }
    // Nothing is hidden and no control appears until something binds the
    // editor. A reader with no script gets the textarea alone.
    assert!(
        css.contains("[data-format=\"markdown\"] > .form-editor-modes {\n    display: none;\n}")
    );
    assert!(css.contains(
        "[data-format=\"markdown\"][data-ready] > .form-editor-modes {\n    display: block;\n}"
    ));
    assert!(css.contains(
        "[data-ready][data-mode=\"preview\"] > .form-editor-preview {\n    display: block;\n}"
    ));
    assert!(css.contains("[data-ready][data-mode=\"preview\"] > .field {\n    display: none;\n}"));
    // No magnitude, the line this crate holds everywhere else.
    assert!(!css.contains("px"), "{css}");
    assert!(!css.contains("rem"), "{css}");
}

/// The prefix reaches the chrome's classes, and the gate deliberately does
/// not: an app assembling the sheet with its own prefix still has the
/// selector an enhancement finds the editors by.
#[test]
fn the_editor_chrome_is_prefixed_and_its_gate_is_not() {
    let opts = Emit {
        class_prefix: "mk-",
        ..Emit::default()
    };
    let css = editor_rules(&opts);
    assert!(css.contains(".mk-form-editor-modes"), "{css}");
    assert!(css.contains("[data-format=\"markdown\"]"), "{css}");
}

/// Every class the editor's markup carries is one the generated sheet rules,
/// so the vocabulary seal picks them up from the sheet itself.
#[test]
fn the_editor_classes_are_in_the_vocabulary() {
    let opts = Emit::default();
    let names = crate::vocabulary::names(&opts);
    for name in ["form-editor-modes", "form-editor-preview", "segment"] {
        assert!(names.contains(name), "{name} is not in the vocabulary");
    }
}

/// Every class a field's markup can carry has a rule in the generated sheet.
#[test]
fn every_field_class_has_a_rule() {
    let css = crate::stylesheet(&Emit::default());
    for name in FIELD_CLASSES {
        assert!(css.contains(&format!(".{name}")), "{name} has no rule");
    }
}

/// Each candidate takes its own line, with its detail at the end of it.
/// Without placement the entries were bare anchors that ran together:
/// MNW's discover search drew "Blue HourProjectKickItem".
#[test]
fn a_suggestion_list_stacks_one_candidate_to_a_line() {
    let css = suggestion_rules(&Emit::default());
    assert!(
        css.contains(".form-suggestions {\n    display: flex;\n    flex-direction: column;\n}"),
        "{css}"
    );
    assert!(
        css.contains(".form-suggestion {\n    display: flex;"),
        "{css}"
    );
    assert!(css.contains("justify-content: space-between;"), "{css}");
}