use serde_json::Value;
use super::a;
use super::linear::titles::*;
use super::tui::{Tui, eventually};
fn json(text: String) -> Value {
serde_json::from_str(&text).unwrap_or_else(|e| panic!("{e}: {text}"))
}
fn run(tui: &Tui, args: &[&str]) -> String {
tui.cli(args)
.unwrap_or_else(|e| panic!("linear-tui {}: {e}", args.join(" ")))
}
fn identifiers(list: &Value) -> Vec<String> {
list["issues"]
.as_array()
.into_iter()
.flatten()
.filter_map(|i| i["identifier"].as_str().map(String::from))
.collect()
}
#[test]
#[ignore = "touches real Linear workspaces; see tests/e2e/main.rs"]
fn every_list_reads_from_the_command_line() {
let (account, seeded) = a();
let tui = Tui::start(&account, "");
let team = seeded.team_key.as_str();
let crash = seeded.issue(CRASH);
let docs = seeded.issue(DOCS);
let active = json(run(&tui, &["issue", "list", "--team", team, "--json"]));
assert!(identifiers(&active).contains(&crash.to_string()));
assert!(
!identifiers(&active).contains(&docs.to_string()),
"Active hides done work"
);
let all = run(&tui, &["issue", "list", "--team", team, "--preset", "all"]);
assert!(all.contains(docs), "{all}");
let urgent = json(run(
&tui,
&[
"issue",
"list",
"--team",
team,
"--priority",
"urgent",
"--json",
],
));
assert_eq!(identifiers(&urgent), [crash]);
let mine = json(run(&tui, &["issue", "list", "--mine", "--json"]));
assert!(identifiers(&mine).contains(&crash.to_string()));
let project = run(&tui, &["issue", "list", "--project", PROJECT]);
assert!(
project.contains(crash) && project.contains(docs),
"{project}"
);
let in_cycle = tui.issue(crash)["cycle"]["name"]
.as_str()
.unwrap()
.to_string();
let cycle = run(
&tui,
&["issue", "list", "--team", team, "--cycle", &in_cycle],
);
assert!(cycle.contains(crash), "{cycle}");
let view = run(&tui, &["issue", "list", "--view", ISSUE_VIEW]);
assert!(view.contains(seeded.issue(WIND)), "{view}");
eventually("issue search finds the seeded issue", || {
let found = json(run(&tui, &["issue", "search", CRASH, "--json"]));
identifiers(&found)
.contains(&crash.to_string())
.then_some(())
});
let teams = run(&tui, &["team", "list"]);
assert!(teams.contains(team), "{teams}");
let shown = run(&tui, &["team", "show", team]);
for part in ["## States", "In Progress", "## Members", "## Labels", "Bug"] {
assert!(shown.contains(part), "{part} in {shown}");
}
let cycles = run(&tui, &["cycle", "list", "--team", team]);
assert!(cycles.contains(&format!("- {in_cycle} — ")), "{cycles}");
let views = run(&tui, &["view", "list"]);
assert!(
views.contains(ISSUE_VIEW) && views.contains(PROJECT_VIEW),
"{views}"
);
let projects = run(&tui, &["project", "list", "--team", team]);
assert!(projects.contains(PROJECT), "{projects}");
let favorites = run(&tui, &["favorite", "list"]);
assert!(
favorites.contains(&format!("linear-tui project show {PROJECT:?}")),
"{favorites}"
);
}
#[test]
#[ignore = "touches real Linear workspaces; see tests/e2e/main.rs"]
fn a_project_and_its_milestones_are_made_changed_and_deleted() {
let (account, seeded) = a();
let tui = Tui::start(&account, "");
let team = seeded.team_key.as_str();
let name = format!("E2E project {}", std::process::id());
let made = run(
&tui,
&[
"project",
"create",
"--team",
team,
"--name",
&name,
"--status",
"Planned",
"--target",
"2027-03-31",
"--lead",
"me",
],
);
assert!(
made.starts_with(&format!("Created project {name}")),
"{made}"
);
let shown = json(run(&tui, &["project", "show", &name, "--json"]));
assert_eq!(shown["status"]["name"], "Planned");
assert_eq!(shown["target_date"], "2027-03-31");
assert_eq!(shown["lead"], seeded.viewer_name.as_str());
let changed = run(
&tui,
&[
"project",
"update",
&name,
"--status",
"In Progress",
"--target",
"none",
],
);
assert!(
changed.contains(&format!("{name}: status Planned → In Progress")),
"{changed}"
);
let backwards = tui
.cli(&[
"project",
"update",
&name,
"--start",
"2027-05-01",
"--target",
"2027-04-01",
])
.unwrap_err();
assert!(backwards.contains("before the start date"), "{backwards}");
let beta = run(
&tui,
&[
"milestone",
"create",
&name,
"--name",
"Beta",
"--target",
"2027-02-01",
],
);
assert!(
beta.starts_with("Created milestone Beta — target 2027-02-01"),
"{beta}"
);
run(
&tui,
&["milestone", "update", &name, "Beta", "--name", "Beta 1"],
);
let milestones = run(&tui, &["milestone", "list", &name]);
assert!(
milestones.contains("- Beta 1 — target 2027-02-01"),
"{milestones}"
);
let filed = json(run(
&tui,
&[
"issue",
"create",
"--team",
team,
"--title",
"E2E milestone issue",
"--project",
&name,
"--milestone",
"Beta 1",
"--json",
],
));
let id = filed["identifier"]
.as_str()
.expect("the new issue")
.to_string();
assert_eq!(tui.issue(&id)["milestone"]["name"], "Beta 1");
run(&tui, &["issue", "update", &id, "--milestone", "none"]);
assert!(tui.issue(&id)["milestone"].is_null());
run(&tui, &["milestone", "delete", &name, "Beta 1"]);
let milestones = run(&tui, &["milestone", "list", &name]);
assert!(milestones.contains("(none)"), "{milestones}");
let deleted = run(&tui, &["project", "delete", &name]);
assert!(deleted.contains("in Linear's trash"), "{deleted}");
let gone = tui.cli(&["project", "show", &name]).unwrap_err();
assert!(gone.contains("no project"), "{gone}");
}