Panics · P36 Account: handlers in new; gone accounts, workspaces, providers and roles mark none; expiries refuse overflow
This commit is contained in:
1 parent
ad472490e0
commit
e7aec1651e
19 files changed
+476
-518
No files matched your search
+37
-26
@@ -21,8 +21,8 @@ fn accounts(_: &Bench, owner: Entity<Bench>) -> AnyElement {
|
||||
account("home", "Ada", "ada@home.com"),
|
||||
],
|
||||
"ada",
|
||||
move |key, _, cx| say(&owner, key.to_string(), cx),
|
||||
)
|
||||
.on_select(move |key, _, cx| say(&owner, key.to_string(), cx))
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
@@ -48,10 +48,13 @@ fn sessions(_: &Bench, owner: Entity<Bench>) -> AnyElement {
|
||||
current,
|
||||
};
|
||||
let everyone = owner.clone();
|
||||
SessionList::new("sessions", [session("phone", false), session("mac", true)])
|
||||
.on_sign_out(move |key, _, cx| say(&owner, format!("out {key}"), cx))
|
||||
.on_sign_out_others(move |_, cx| say(&everyone, "others".into(), cx))
|
||||
.into_any_element()
|
||||
SessionList::new(
|
||||
"sessions",
|
||||
[session("phone", false), session("mac", true)],
|
||||
move |key, _, cx| say(&owner, format!("out {key}"), cx),
|
||||
)
|
||||
.on_sign_out_others(move |_, cx| say(&everyone, "others".into(), cx))
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
/// Stops: the phone's Sign out, then Sign out of all other devices; this device has none.
|
||||
@@ -81,10 +84,13 @@ fn keys(bench: &Bench, owner: Entity<Bench>) -> AnyElement {
|
||||
used: "Never used".into(),
|
||||
};
|
||||
let [made, revoked, done] = [(); 3].map(|_| owner.clone());
|
||||
let manager = ApiKeyManager::new("keys", [key])
|
||||
.on_create(move |name, _, cx| say(&made, format!("make {name}"), cx))
|
||||
.on_revoke(move |key, _, cx| say(&revoked, format!("revoke {key}"), cx))
|
||||
.on_dismiss(move |_, cx| say(&done, "done".into(), cx));
|
||||
let manager = ApiKeyManager::new(
|
||||
"keys",
|
||||
[key],
|
||||
move |name, _, cx| say(&made, format!("make {name}"), cx),
|
||||
move |key, _, cx| say(&revoked, format!("revoke {key}"), cx),
|
||||
move |_, cx| say(&done, "done".into(), cx),
|
||||
);
|
||||
match bench.sent {
|
||||
true => manager.secret("sk_live_0123456789").into_any_element(),
|
||||
false => manager.into_any_element(),
|
||||
@@ -138,11 +144,10 @@ fn profile() -> Profile {
|
||||
}
|
||||
|
||||
fn editor(_: &Bench, owner: Entity<Bench>) -> AnyElement {
|
||||
ProfileEditor::new("profile", profile())
|
||||
.on_save(move |profile, _, cx| {
|
||||
say(&owner, format!("{} {}", profile.name, profile.email), cx)
|
||||
})
|
||||
.into_any_element()
|
||||
ProfileEditor::new("profile", profile(), move |profile, _, cx| {
|
||||
say(&owner, format!("{} {}", profile.name, profile.email), cx)
|
||||
})
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
/// Stops: the picture, name, username, email, about, location; Discard and Save once changed.
|
||||
@@ -167,10 +172,11 @@ fn a_profile_saves_only_what_changed_and_discard_puts_it_back(cx: &mut TestAppCo
|
||||
|
||||
fn menu(_: &Bench, owner: Entity<Bench>) -> AnyElement {
|
||||
let [profile, out] = [(); 2].map(|_| owner.clone());
|
||||
UserMenu::new("user", "Ada", "ada@example.com")
|
||||
.item(MenuItem::new("Profile").on_click(move |_, cx| say(&profile, "profile".into(), cx)))
|
||||
.on_sign_out(move |_, cx| say(&out, "out".into(), cx))
|
||||
.into_any_element()
|
||||
UserMenu::new("user", "Ada", "ada@example.com", move |_, cx| {
|
||||
say(&out, "out".into(), cx)
|
||||
})
|
||||
.item(MenuItem::new("Profile").on_click(move |_, cx| say(&profile, "profile".into(), cx)))
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
/// Stops: the avatar; the menu's rows are Profile, then Sign out.
|
||||
@@ -191,10 +197,14 @@ fn workspaces(_: &Bench, owner: Entity<Bench>) -> AnyElement {
|
||||
detail: "Pro".into(),
|
||||
};
|
||||
let made = owner.clone();
|
||||
WorkspaceSwitcher::new("spaces", [space("north"), space("south")], "south")
|
||||
.on_select(move |key, _, cx| say(&owner, key.to_string(), cx))
|
||||
.on_create(move |_, cx| say(&made, "create".into(), cx))
|
||||
.into_any_element()
|
||||
WorkspaceSwitcher::new(
|
||||
"spaces",
|
||||
[space("north"), space("south")],
|
||||
"south",
|
||||
move |key, _, cx| say(&owner, key.to_string(), cx),
|
||||
)
|
||||
.on_create(move |_, cx| say(&made, "create".into(), cx))
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
/// Stops: the switcher; its rows are north, south, then Create workspace.
|
||||
@@ -222,10 +232,11 @@ fn alone(_: &Bench, owner: Entity<Bench>) -> AnyElement {
|
||||
current: true,
|
||||
};
|
||||
let everyone = owner.clone();
|
||||
SessionList::new("sessions", [here])
|
||||
.on_sign_out(move |key, _, cx| say(&owner, format!("out {key}"), cx))
|
||||
.on_sign_out_others(move |_, cx| say(&everyone, "others".into(), cx))
|
||||
.into_any_element()
|
||||
SessionList::new("sessions", [here], move |key, _, cx| {
|
||||
say(&owner, format!("out {key}"), cx)
|
||||
})
|
||||
.on_sign_out_others(move |_, cx| say(&everyone, "others".into(), cx))
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
/// With this device alone there is nothing to sign out, so the list has no stop.
|
||||
|
||||
+152
-38
@@ -51,23 +51,22 @@ fn a_plan_cancels_on_the_second_press_and_comes_back(cx: &mut TestAppContext) {
|
||||
}
|
||||
|
||||
fn card(_: &Bench, owner: Entity<Bench>) -> AnyElement {
|
||||
PaymentMethodForm::new("card")
|
||||
.on_submit(move |card, _, cx| {
|
||||
say(
|
||||
&owner,
|
||||
format!(
|
||||
"{} {} {}/{} {} {}",
|
||||
card.brand.name(),
|
||||
card.number,
|
||||
card.month,
|
||||
card.year,
|
||||
card.cvc,
|
||||
card.name
|
||||
),
|
||||
cx,
|
||||
)
|
||||
})
|
||||
.into_any_element()
|
||||
PaymentMethodForm::new("card", move |card, _, cx| {
|
||||
say(
|
||||
&owner,
|
||||
format!(
|
||||
"{} {} {}/{} {} {}",
|
||||
card.brand.name(),
|
||||
card.number,
|
||||
card.month,
|
||||
card.year,
|
||||
card.cvc,
|
||||
card.name
|
||||
),
|
||||
cx,
|
||||
)
|
||||
})
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
/// Stops: number, expiry, code, name, then Save once the card reads.
|
||||
@@ -116,11 +115,15 @@ fn invites(_: &Bench, owner: Entity<Bench>) -> AnyElement {
|
||||
expired: false,
|
||||
};
|
||||
let [invited, again, gone] = [(); 3].map(|_| owner.clone());
|
||||
InvitationList::new("invites", [sent], roles())
|
||||
.on_invite(move |email, role, _, cx| say(&invited, format!("invite {email} {role}"), cx))
|
||||
.on_resend(move |key, _, cx| say(&again, format!("resend {key}"), cx))
|
||||
.on_revoke(move |key, _, cx| say(&gone, format!("revoke {key}"), cx))
|
||||
.into_any_element()
|
||||
InvitationList::new(
|
||||
"invites",
|
||||
[sent],
|
||||
roles(),
|
||||
move |email, role, _, cx| say(&invited, format!("invite {email} {role}"), cx),
|
||||
move |key, _, cx| say(&again, format!("resend {key}"), cx),
|
||||
move |key, _, cx| say(&gone, format!("revoke {key}"), cx),
|
||||
)
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
/// Stops: the address, the role, then Resend and Revoke while Invite rests.
|
||||
@@ -149,10 +152,14 @@ fn team(_: &Bench, owner: Entity<Bench>) -> AnyElement {
|
||||
owner,
|
||||
};
|
||||
let removed = owner.clone();
|
||||
TeamMemberTable::new("team", [member("ada", true), member("bo", false)], roles())
|
||||
.on_role(move |key, role, _, cx| say(&owner, format!("{key} {role}"), cx))
|
||||
.on_remove(move |key, _, cx| say(&removed, format!("remove {key}"), cx))
|
||||
.into_any_element()
|
||||
TeamMemberTable::new(
|
||||
"team",
|
||||
[member("ada", true), member("bo", false)],
|
||||
roles(),
|
||||
move |key, role, _, cx| say(&owner, format!("{key} {role}"), cx),
|
||||
move |key, _, cx| say(&removed, format!("remove {key}"), cx),
|
||||
)
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
/// Stops: bo's role, then bo's Remove; the owner has neither.
|
||||
@@ -167,11 +174,12 @@ fn a_member_leaves_on_the_second_press_and_the_owner_stays(cx: &mut TestAppConte
|
||||
|
||||
fn wall(_: &Bench, owner: Entity<Bench>) -> AnyElement {
|
||||
let later = owner.clone();
|
||||
UpgradePrompt::new("wall", "Unlock history")
|
||||
.benefit("Every message, kept")
|
||||
.on_upgrade(move |_, cx| say(&owner, "upgrade".into(), cx))
|
||||
.on_dismiss(move |_, cx| say(&later, "later".into(), cx))
|
||||
.into_any_element()
|
||||
UpgradePrompt::new("wall", "Unlock history", move |_, cx| {
|
||||
say(&owner, "upgrade".into(), cx)
|
||||
})
|
||||
.benefit("Every message, kept")
|
||||
.on_dismiss(move |_, cx| say(&later, "later".into(), cx))
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
/// Stops: Upgrade, then Not now.
|
||||
@@ -186,10 +194,11 @@ fn a_paywall_upgrades_or_waits(cx: &mut TestAppContext) {
|
||||
}
|
||||
|
||||
fn busy_card(_: &Bench, owner: Entity<Bench>) -> AnyElement {
|
||||
PaymentMethodForm::new("card")
|
||||
.busy(true)
|
||||
.on_submit(move |card, _, cx| say(&owner, card.number.to_string(), cx))
|
||||
.into_any_element()
|
||||
PaymentMethodForm::new("card", move |card, _, cx| {
|
||||
say(&owner, card.number.to_string(), cx)
|
||||
})
|
||||
.busy(true)
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
/// Stops: number, expiry, code, name; Save rests while the owner checks the card.
|
||||
@@ -354,9 +363,10 @@ fn a_quota_past_its_limit_draws_full(cx: &mut TestAppContext) {
|
||||
}
|
||||
|
||||
fn line(_: &Bench, owner: Entity<Bench>) -> AnyElement {
|
||||
UpgradePrompt::new("line", "Unlock history")
|
||||
.on_upgrade(move |_, cx| say(&owner, "upgrade".into(), cx))
|
||||
.into_any_element()
|
||||
UpgradePrompt::new("line", "Unlock history", move |_, cx| {
|
||||
say(&owner, "upgrade".into(), cx)
|
||||
})
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
/// With benefits the prompt is a paywall that lists them.
|
||||
@@ -372,3 +382,107 @@ fn a_prompt_without_benefits_stands_as_a_line(cx: &mut TestAppContext) {
|
||||
let (_, cx) = bench(line, cx);
|
||||
assert!(cx.debug_bounds("paywall-benefits").is_none());
|
||||
}
|
||||
|
||||
/// Accounts, workspaces, a provider and roles that left their lists.
|
||||
fn departed(_: &Bench, _: Entity<Bench>) -> AnyElement {
|
||||
let account = crate::account::Account {
|
||||
key: "ada".into(),
|
||||
name: "Ada".into(),
|
||||
email: "ada@work.com".into(),
|
||||
image: None,
|
||||
};
|
||||
let space = crate::account::Workspace {
|
||||
key: "north".into(),
|
||||
name: "North".into(),
|
||||
detail: "Pro".into(),
|
||||
};
|
||||
let invitation = Invitation {
|
||||
key: "bo".into(),
|
||||
email: "bo@example.com".into(),
|
||||
role: "gone".into(),
|
||||
sent: "Sent 2 days ago".into(),
|
||||
expired: false,
|
||||
};
|
||||
let member = Member {
|
||||
key: "bo".into(),
|
||||
name: "Bo".into(),
|
||||
email: "bo@example.com".into(),
|
||||
role: "gone".into(),
|
||||
seen: "Active today".into(),
|
||||
image: None,
|
||||
owner: false,
|
||||
};
|
||||
div()
|
||||
.w(px(360.0))
|
||||
.child(crate::account::AccountSwitcher::new(
|
||||
"accounts",
|
||||
[account],
|
||||
"gone",
|
||||
|_, _, _| {},
|
||||
))
|
||||
.child(crate::account::WorkspaceSwitcher::new(
|
||||
"spaces",
|
||||
[space],
|
||||
"gone",
|
||||
|_, _, _| {},
|
||||
))
|
||||
.child(
|
||||
crate::account::OAuthButtons::new("oauth", [("github", "GitHub")], |_, _, _| {})
|
||||
.busy("gone"),
|
||||
)
|
||||
.child(InvitationList::new(
|
||||
"invites",
|
||||
[invitation],
|
||||
roles(),
|
||||
|_, _, _, _| {},
|
||||
|_, _, _| {},
|
||||
|_, _, _| {},
|
||||
))
|
||||
.child(TeamMemberTable::new(
|
||||
"team",
|
||||
[member],
|
||||
roles(),
|
||||
|_, _, _, _| {},
|
||||
|_, _, _| {},
|
||||
))
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn accounts_workspaces_and_roles_that_left_draw(cx: &mut TestAppContext) {
|
||||
let (_, cx) = bench(departed, cx);
|
||||
settle(cx);
|
||||
}
|
||||
|
||||
/// Invitations whose first role leaves once the bench says sent.
|
||||
fn departing_role(state: &Bench, owner: Entity<Bench>) -> AnyElement {
|
||||
let offered: Vec<Role> = roles()
|
||||
.into_iter()
|
||||
.filter(|role| !state.sent || role.key != "member")
|
||||
.collect();
|
||||
InvitationList::new(
|
||||
"invites",
|
||||
[],
|
||||
offered,
|
||||
move |email, role, _, cx| say(&owner, format!("invite {email} {role}"), cx),
|
||||
|_, _, _| {},
|
||||
|_, _, _| {},
|
||||
)
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn an_invitation_as_a_role_that_left_sends_nothing(cx: &mut TestAppContext) {
|
||||
let (host, cx) = bench(departing_role, cx);
|
||||
tab(1, cx);
|
||||
write("cy@example.com", cx);
|
||||
host.update(cx, |state, cx| {
|
||||
state.sent = true;
|
||||
cx.notify();
|
||||
});
|
||||
settle(cx);
|
||||
tap("enter", cx);
|
||||
tab(3, cx);
|
||||
tap("space", cx);
|
||||
assert_eq!(said(&host, cx), Vec::<String>::new());
|
||||
}
|
||||
@@ -6,16 +6,15 @@ use crate::account::{
|
||||
};
|
||||
|
||||
fn login(_: &Bench, owner: Entity<Bench>) -> AnyElement {
|
||||
LoginForm::new("login")
|
||||
.on_submit(move |login, _, cx| {
|
||||
say(
|
||||
&owner,
|
||||
format!("{} {} {}", login.email, login.password, login.remember),
|
||||
cx,
|
||||
)
|
||||
})
|
||||
.on_forgot(|_, _| {})
|
||||
.into_any_element()
|
||||
LoginForm::new("login", move |login, _, cx| {
|
||||
say(
|
||||
&owner,
|
||||
format!("{} {} {}", login.email, login.password, login.remember),
|
||||
cx,
|
||||
)
|
||||
})
|
||||
.on_forgot(|_, _| {})
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
/// Stops: email, password, its eye, the box, the forgotten password, Sign in.
|
||||
@@ -41,16 +40,15 @@ fn sign_in_waits_for_an_address_and_a_password_and_enter_sends(cx: &mut TestAppC
|
||||
}
|
||||
|
||||
fn signup(_: &Bench, owner: Entity<Bench>) -> AnyElement {
|
||||
SignupForm::new("signup")
|
||||
.terms("I agree to the terms")
|
||||
.on_submit(move |signup, _, cx| {
|
||||
say(
|
||||
&owner,
|
||||
format!("{} {} {}", signup.name, signup.email, signup.password),
|
||||
cx,
|
||||
)
|
||||
})
|
||||
.into_any_element()
|
||||
SignupForm::new("signup", move |signup, _, cx| {
|
||||
say(
|
||||
&owner,
|
||||
format!("{} {} {}", signup.name, signup.email, signup.password),
|
||||
cx,
|
||||
)
|
||||
})
|
||||
.terms("I agree to the terms")
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
/// Stops: name, email, password, its eye, the terms, then Create account once it holds.
|
||||
@@ -80,8 +78,11 @@ fn sign_up_waits_for_every_rule_and_the_terms(cx: &mut TestAppContext) {
|
||||
}
|
||||
|
||||
fn providers(bench: &Bench, owner: Entity<Bench>) -> AnyElement {
|
||||
let buttons = OAuthButtons::new("oauth", [("github", "GitHub"), ("google", "Google")])
|
||||
.on_pick(move |key, _, cx| say(&owner, key.to_string(), cx));
|
||||
let buttons = OAuthButtons::new(
|
||||
"oauth",
|
||||
[("github", "GitHub"), ("google", "Google")],
|
||||
move |key, _, cx| say(&owner, key.to_string(), cx),
|
||||
);
|
||||
match bench.sent {
|
||||
true => buttons.busy("github").into_any_element(),
|
||||
false => buttons.into_any_element(),
|
||||
@@ -113,19 +114,18 @@ fn a_provider_hands_its_key_and_rests_while_one_is_on_its_way(cx: &mut TestAppCo
|
||||
|
||||
fn magic(bench: &Bench, owner: Entity<Bench>) -> AnyElement {
|
||||
let other = owner.clone();
|
||||
MagicLinkForm::new("magic")
|
||||
.sent(bench.sent)
|
||||
.on_send(move |address, _, cx| {
|
||||
say(&owner, format!("send {address}"), cx);
|
||||
owner.update(cx, |bench, _| bench.sent = true);
|
||||
MagicLinkForm::new("magic", move |address, _, cx| {
|
||||
say(&owner, format!("send {address}"), cx);
|
||||
owner.update(cx, |bench, _| bench.sent = true);
|
||||
})
|
||||
.sent(bench.sent)
|
||||
.on_other(move |_, cx| {
|
||||
other.update(cx, |bench, cx| {
|
||||
bench.sent = false;
|
||||
cx.notify();
|
||||
})
|
||||
.on_other(move |_, cx| {
|
||||
other.update(cx, |bench, cx| {
|
||||
bench.sent = false;
|
||||
cx.notify();
|
||||
})
|
||||
})
|
||||
.into_any_element()
|
||||
})
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
/// Stops: email, then the link button; once sent, Send again and Use another email.
|
||||
@@ -151,11 +151,12 @@ fn a_link_goes_to_the_address_and_again_on_request(cx: &mut TestAppContext) {
|
||||
|
||||
fn forgot(bench: &Bench, owner: Entity<Bench>) -> AnyElement {
|
||||
let back = owner.clone();
|
||||
ForgotPassword::new("forgot")
|
||||
.sent(bench.sent)
|
||||
.on_send(move |address, _, cx| say(&owner, format!("reset {address}"), cx))
|
||||
.on_back(move |_, cx| say(&back, "back".into(), cx))
|
||||
.into_any_element()
|
||||
ForgotPassword::new("forgot", move |address, _, cx| {
|
||||
say(&owner, format!("reset {address}"), cx)
|
||||
})
|
||||
.sent(bench.sent)
|
||||
.on_back(move |_, cx| say(&back, "back".into(), cx))
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
/// Stops: email, then Back to sign in while the send rests.
|
||||
@@ -172,10 +173,11 @@ fn a_reset_waits_for_an_address_and_offers_the_way_back(cx: &mut TestAppContext)
|
||||
}
|
||||
|
||||
fn factor(bench: &Bench, owner: Entity<Bench>) -> AnyElement {
|
||||
TwoFactorInput::new("factor")
|
||||
.failed(bench.failed)
|
||||
.on_code(move |code, _, cx| say(&owner, code.to_string(), cx))
|
||||
.into_any_element()
|
||||
TwoFactorInput::new("factor", move |code, _, cx| {
|
||||
say(&owner, code.to_string(), cx)
|
||||
})
|
||||
.failed(bench.failed)
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
/// Stops: the code.
|
||||
@@ -207,10 +209,11 @@ fn sign_in_waits_for_a_password(cx: &mut TestAppContext) {
|
||||
}
|
||||
|
||||
fn busy_login(_: &Bench, owner: Entity<Bench>) -> AnyElement {
|
||||
LoginForm::new("login")
|
||||
.busy(true)
|
||||
.on_submit(move |login, _, cx| say(&owner, login.email.to_string(), cx))
|
||||
.into_any_element()
|
||||
LoginForm::new("login", move |login, _, cx| {
|
||||
say(&owner, login.email.to_string(), cx)
|
||||
})
|
||||
.busy(true)
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
/// Stops: email, password, its eye, the box; Sign in rests while busy, so a fifth Tab wraps to the email.
|
||||
@@ -248,12 +251,13 @@ fn sign_up_waits_for_a_name(cx: &mut TestAppContext) {
|
||||
|
||||
fn busy_sent(_: &Bench, owner: Entity<Bench>) -> AnyElement {
|
||||
let other = owner.clone();
|
||||
MagicLinkForm::new("magic")
|
||||
.sent(true)
|
||||
.busy(true)
|
||||
.on_send(move |address, _, cx| say(&owner, format!("send {address}"), cx))
|
||||
.on_other(move |_, cx| say(&other, "other".into(), cx))
|
||||
.into_any_element()
|
||||
MagicLinkForm::new("magic", move |address, _, cx| {
|
||||
say(&owner, format!("send {address}"), cx)
|
||||
})
|
||||
.sent(true)
|
||||
.busy(true)
|
||||
.on_other(move |_, cx| say(&other, "other".into(), cx))
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
/// While a link is on its way Send again rests, so the first stop is Use another email.
|
||||
|
||||
Reference in new issue
Block a user