//! End-to-end smoke test: login → whoami → apps create → apps ls → //! scripts deploy (create + update) → scripts ls → scripts invoke → //! logs. The original seed test, refactored to run against the shared //! fixture so subsequent journey modules don't each pay for a server //! spawn. #![allow(clippy::too_many_lines)] use predicates::prelude::*; use serde_json::Value; use crate::common; use crate::common::cleanup::AppGuard; #[ignore = "needs DATABASE_URL pointing at a running Postgres"] #[test] fn end_to_end_login_deploy_invoke_logs() { let Some(fx) = common::fixture_or_skip() else { return; }; let env = common::admin_env(fx); let slug = common::unique_slug("e2e"); let username = &fx.admin_username; // 1) login common::pic_as(&env) .args(["login"]) .assert() .success() .stdout(predicate::str::contains(format!("Logged in as {username}"))); let creds_path = env.config_dir.path().join("credentials"); assert!( creds_path.exists(), "credentials file should exist after login" ); let body = std::fs::read_to_string(&creds_path).unwrap(); assert!(body.contains(&env.url), "creds should contain url: {body}"); assert!( body.contains(username.as_str()), "creds should contain username: {body}" ); // 2) whoami common::pic_as(&env) .args(["whoami"]) .assert() .success() .stdout(predicate::str::contains(username.clone())); // 3) apps create common::pic_as(&env) .args(["apps", "create", &slug]) .assert() .success() .stdout(predicate::str::contains(format!("Created app {slug}"))); // Cleanup no matter what subsequent assertions do. let _guard = AppGuard::new(&env.url, &env.token, &slug); // 4) apps ls common::pic_as(&env) .args(["apps", "ls"]) .assert() .success() .stdout(predicate::str::contains(slug.as_str())); // 5) scripts deploy (create then update) let fixture = common::fixture_path("hello.rhai"); common::pic_as(&env) .args([ "scripts", "deploy", fixture.to_str().unwrap(), "--app", &slug, ]) .assert() .success() .stdout(predicate::str::contains("Created hello v1")); common::pic_as(&env) .args([ "scripts", "deploy", fixture.to_str().unwrap(), "--app", &slug, ]) .assert() .success() .stdout(predicate::str::contains("Updated hello v2")); // 6) scripts ls and capture the id let ls_out = common::pic_as(&env) .args(["scripts", "ls", "--app", &slug]) .output() .expect("scripts ls"); assert!(ls_out.status.success(), "scripts ls failed: {ls_out:?}"); let id = common::parse_first_id(std::str::from_utf8(&ls_out.stdout).unwrap()) .expect("scripts ls should print at least one row"); // 7) invoke let invoke_out = common::pic_as(&env) .args(["scripts", "invoke", &id]) .output() .expect("scripts invoke"); assert!( invoke_out.status.success(), "invoke failed: {}", String::from_utf8_lossy(&invoke_out.stderr) ); let parsed: Value = serde_json::from_slice(&invoke_out.stdout).expect("invoke stdout should be JSON"); assert_eq!( parsed["ok"], true, "expected hello.rhai response, got {parsed}" ); // 8) logs (the invoke above should have produced exactly one row) let logs_out = common::pic_as(&env) .args(["logs", &id]) .output() .expect("pic logs"); assert!(logs_out.status.success(), "logs failed: {logs_out:?}"); let stdout = String::from_utf8_lossy(&logs_out.stdout); assert!( stdout.lines().any(|l| !l.trim().is_empty()), "logs should have at least one row, got: {stdout}" ); }