#!/usr/bin/env bash # End-to-end checks of the Etappe-2a Divi read tools through the OAuth-protected endpoint. # Runs INSIDE the DDEV web container (Divi 5 must be the active theme): # cd /home/janniclas/Projekte/WordPress && timeout 600 ddev exec bash wp-content/plugins/WP-LIT-MCP/tests/Integration/divi-read-smoke.sh # Creates draft pages from tests/Fixtures/divi and deletes them again. set -euo pipefail cd /var/www/html # shellcheck source=lib.sh source wp-content/plugins/WP-LIT-MCP/tests/Integration/lib.sh ADMIN_LOGIN=$(wp user list --role=administrator --field=user_login | head -1) FIXTURES=$PLUGIN/tests/Fixtures/divi CREATED_POSTS=() cleanup() { for id in "${CREATED_POSTS[@]}"; do wp post delete "$id" --force >/dev/null 2>&1 || true done cleanup_app_passwords_for "$ADMIN_LOGIN" } trap cleanup EXIT # Creates a draft page from a fixture file as the admin (no kses re-serialization) and prints its ID. create_page() { # $1 = fixture file, $2 = title LIT_FILE="$FIXTURES/$1" LIT_TITLE="$2" wp --user="$ADMIN_LOGIN" eval ' $id = wp_insert_post(["post_type" => "page", "post_status" => "draft", "post_title" => getenv("LIT_TITLE"), "post_content" => wp_slash((string) file_get_contents(getenv("LIT_FILE")))]); update_post_meta($id, "_et_pb_use_builder", "on"); update_post_meta($id, "_et_pb_use_divi_5", "on"); echo $id;' } content_hash() { # $1 = post ID -> tree_rev of the stored content wp eval "echo substr(hash('sha256', (string) get_post($1)->post_content), 0, 12);" } [ "$(wp eval 'echo get_template();')" = "Divi" ] || fail "Divi must be the active theme" wp eval-file "$PLUGIN/tests/Integration/divi-shortform-check.php" >/dev/null || fail "short form does not match the Divi catalog" pass "short form matches the live Divi catalog" PAGE_ID=$(create_page converted-landing.html "LIT Divi Lesen") CREATED_POSTS+=("$PAGE_ID") D4_ID=$(create_page divi4-shortcodes.html "LIT Divi 4") CREATED_POSTS+=("$D4_ID") BEFORE=$(content_hash "$PAGE_ID") connect "$ADMIN_LOGIN" # 1. Direct read tools with readOnlyHint LIST=$(rpc tools/list '{}') for t in lit-divi-outline lit-divi-node-get lit-divi-catalog lit-divi-design-system lit-page-render-summary; do echo "$LIST" | jq -e --arg t "$t" '.result.tools[] | select(.name == $t) | .annotations.readOnlyHint == true' >/dev/null \ || fail "tools/list lacks $t with readOnlyHint" done pass "tools/list: Divi read tools are direct and read-only" # 2. Outline with tree_rev = hash of post_content (ruling P16) and path IDs OUTLINE=$(tool lit-divi-outline "{\"post_id\":$PAGE_ID}") [ "$(echo "$OUTLINE" | jq -r '.tree_rev')" = "$BEFORE" ] || fail "tree_rev is not the hash of post_content: $OUTLINE" echo "$OUTLINE" | jq -e '.rev != .tree_rev' >/dev/null || fail "rev and tree_rev must differ: $OUTLINE" echo "$OUTLINE" | jq -e '.nodes[] | select(.id == "s1.r1.c0.m2.m0" and .type == "accordion-item")' >/dev/null \ || fail "outline lacks the accordion item: $OUTLINE" echo "$OUTLINE" | jq -r '.outline' | head -1 | grep -q '^s0 section "Hero"' || fail "outline text: $OUTLINE" pass "lit-divi-outline: path IDs, tree_rev, rev" # 3. Node in full form plus short-form values NODE=$(tool lit-divi-node-get "{\"post_id\":$PAGE_ID,\"id\":\"s0.r0.c0.m0\"}") echo "$NODE" | jq -e '.type == "heading" and .shortform.text == "Handwerk mit Herz"' >/dev/null || fail "node-get: $NODE" echo "$NODE" | jq -e '.rev | length == 12' >/dev/null || fail "node-get rev: $NODE" echo "$NODE" | jq -e '.attrs["title.innerContent"].desktop.value == "Handwerk mit Herz"' >/dev/null || fail "node-get attrs: $NODE" MISSING=$(tool lit-divi-node-get "{\"post_id\":$PAGE_ID,\"id\":\"s9\"}") [ "$(error_code "$MISSING")" = "not_found" ] || fail "unknown node: $MISSING" pass "lit-divi-node-get: full form, short form, unknown node" # 4. Catalog and design system live from Divi CATALOG=$(tool lit-divi-catalog '{}') echo "$CATALOG" | jq -e '(.modules | length) >= 90' >/dev/null || fail "catalog too small: $CATALOG" BUTTON=$(tool lit-divi-catalog '{"module":"button"}') echo "$BUTTON" | jq -e '.module.paths | index("button.innerContent") != null' >/dev/null || fail "catalog button: $BUTTON" DESIGN=$(tool lit-divi-design-system '{}') echo "$DESIGN" | jq -e '.colors[] | select(.id == "gcid-primary-color" and .placeholder == "{{color:primary}}")' >/dev/null \ || fail "design system: $DESIGN" pass "lit-divi-catalog and lit-divi-design-system read live data" # 5. Rendered summary SUMMARY=$(tool lit-page-render-summary "{\"post_id\":$PAGE_ID}") echo "$SUMMARY" | jq -e '.headings[0].text == "Handwerk mit Herz"' >/dev/null || fail "render summary: $SUMMARY" echo "$SUMMARY" | jq -e '[.texts[] | select(contains("Seit 1987"))] | length == 1' >/dev/null || fail "render texts: $SUMMARY" pass "lit-page-render-summary renders Divi modules" # 6. Hints and refusals GET=$(tool lit-content-get "{\"post_id\":$PAGE_ID}") echo "$GET" | jq -e '.content == null and (.hints[0] | contains("lit-divi-outline"))' >/dev/null || fail "content-get hint: $GET" D4=$(tool lit-divi-outline "{\"post_id\":$D4_ID}") [ "$(error_code "$D4")" = "unsupported" ] || fail "Divi 4 page must be unsupported: $D4" pass "content-get points to the Divi tools; Divi 4 content is refused" # 7. Reading changed nothing [ "$(content_hash "$PAGE_ID")" = "$BEFORE" ] || fail "reading changed post_content" pass "post_content unchanged after reading" echo "ALL CHECKS PASSED"