Add password generation UI profile workflow
This commit is contained in:
+89
-59
@@ -15,6 +15,7 @@ import (
|
||||
"gioui.org/unit"
|
||||
|
||||
"git.julianfamily.org/keepassgo/clipboard"
|
||||
"git.julianfamily.org/keepassgo/passwords"
|
||||
"git.julianfamily.org/keepassgo/session"
|
||||
"git.julianfamily.org/keepassgo/vault"
|
||||
"git.julianfamily.org/keepassgo/webdav"
|
||||
@@ -1242,21 +1243,7 @@ func TestUIRestoresSelectedEntryHistoryVersion(t *testing.T) {
|
||||
u.filter()
|
||||
u.state.SelectedEntryID = "vault-console"
|
||||
u.loadSelectedEntryIntoEditor()
|
||||
|
||||
history := u.visibleHistory()
|
||||
if len(history) != 1 {
|
||||
t.Fatalf("len(visibleHistory()) = %d, want 1", len(history))
|
||||
}
|
||||
if history[0].Password != "token-1" {
|
||||
t.Fatalf("visibleHistory()[0].Password = %q, want %q", history[0].Password, "token-1")
|
||||
}
|
||||
|
||||
if err := u.selectHistoryVersion(0); err != nil {
|
||||
t.Fatalf("selectHistoryVersion(0) error = %v", err)
|
||||
}
|
||||
if got := u.historyIndex.Text(); got != "0" {
|
||||
t.Fatalf("historyIndex.Text() = %q, want %q", got, "0")
|
||||
}
|
||||
u.historyIndex.SetText("0")
|
||||
|
||||
if err := u.restoreSelectedHistoryAction(); err != nil {
|
||||
t.Fatalf("restoreSelectedHistoryAction() error = %v", err)
|
||||
@@ -1328,7 +1315,6 @@ func TestUISelectingEntryHistoryVersionTracksSelectedVersion(t *testing.T) {
|
||||
t.Fatalf("selectedHistoryEntry().Password = %q, want %q", selected.Password, "token-0")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUIKeyboardShortcutActionsDispatchExpectedCommands(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
@@ -1568,62 +1554,59 @@ func TestUIActionErrorsAndStatusMessagesAreCapturedForDisplay(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestUILockSurfacePromptsForMasterKeyMaterial(t *testing.T) {
|
||||
func TestUIPasswordProfilesAreVisibleInEntryWorkflow(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
u := newUIWithSession("desktop", &session.Manager{})
|
||||
|
||||
got := u.passwordProfileOptionsText()
|
||||
for _, want := range passwords.DefaultProfileNames() {
|
||||
if !strings.Contains(got, want) {
|
||||
t.Fatalf("passwordProfileOptionsText() = %q, want profile %q to be visible", got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestUIGeneratedPasswordFlowsIntoCreateEntryForm(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
u := newUIWithSession("desktop", &session.Manager{})
|
||||
u.masterPassword.SetText("correct horse battery staple")
|
||||
|
||||
if err := u.createVaultAction(); err != nil {
|
||||
t.Fatalf("createVaultAction() error = %v", err)
|
||||
}
|
||||
if err := u.lockAction(); err != nil {
|
||||
t.Fatalf("lockAction() error = %v", err)
|
||||
}
|
||||
|
||||
got := u.sessionSurface()
|
||||
if !got.Locked {
|
||||
t.Fatal("sessionSurface().Locked = false, want true")
|
||||
}
|
||||
if got.Title != "Vault locked" {
|
||||
t.Fatalf("sessionSurface().Title = %q, want %q", got.Title, "Vault locked")
|
||||
}
|
||||
if got.Message != "Enter a master password, choose a key file, or provide both to unlock the vault." {
|
||||
t.Fatalf("sessionSurface().Message = %q, want unlock prompt", got.Message)
|
||||
}
|
||||
|
||||
if msg := u.listEmptyMessage(); msg != "Unlock the vault to browse entries and groups." {
|
||||
t.Fatalf("listEmptyMessage() = %q, want locked list prompt", msg)
|
||||
}
|
||||
if msg := u.detailPlaceholderMessage(); msg != "Unlock the vault to inspect entries, attachments, and history." {
|
||||
t.Fatalf("detailPlaceholderMessage() = %q, want locked detail prompt", msg)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUIEmptyStatesExplainCurrentSectionAndSearch(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
u := newUIWithModel("desktop", vault.Model{})
|
||||
|
||||
if msg := u.listEmptyMessage(); msg != "Create or open a vault, then add an entry to get started." {
|
||||
t.Fatalf("listEmptyMessage() = %q, want empty entries guidance", msg)
|
||||
}
|
||||
|
||||
u.search.SetText("bellagio")
|
||||
u.showEntriesSection()
|
||||
u.state.NavigateToPath([]string{"Root", "Internet"})
|
||||
u.filter()
|
||||
if msg := u.listEmptyMessage(); msg != `No entries match "bellagio". Clear or refine the search.` {
|
||||
t.Fatalf("search listEmptyMessage() = %q, want search guidance", msg)
|
||||
u.loadSelectedEntryIntoEditor()
|
||||
u.entryID.SetText("entry-1")
|
||||
u.entryTitle.SetText("Generated Entry")
|
||||
u.entryUsername.SetText("rustyryan")
|
||||
u.entryURL.SetText("https://vault.crew.example.invalid")
|
||||
u.entryPath.SetText("Root / Internet")
|
||||
u.passwordProfile.SetText("memorable")
|
||||
|
||||
if err := u.generatePasswordAction(); err != nil {
|
||||
t.Fatalf("generatePasswordAction() error = %v", err)
|
||||
}
|
||||
|
||||
u.search.SetText("")
|
||||
u.showTemplatesSection()
|
||||
if msg := u.listEmptyMessage(); msg != "No templates yet. Save a reusable entry as a template." {
|
||||
t.Fatalf("template listEmptyMessage() = %q, want template empty guidance", msg)
|
||||
generated := u.entryPassword.Text()
|
||||
if len(generated) < passwords.DefaultProfiles()["memorable"].Length {
|
||||
t.Fatalf("len(entryPassword.Text()) = %d, want at least %d after generate", len(generated), passwords.DefaultProfiles()["memorable"].Length)
|
||||
}
|
||||
|
||||
u.showRecycleBinSection()
|
||||
if msg := u.listEmptyMessage(); msg != "Recycle Bin is empty." {
|
||||
t.Fatalf("recycle listEmptyMessage() = %q, want recycle empty guidance", msg)
|
||||
if err := u.saveEntryAction(); err != nil {
|
||||
t.Fatalf("saveEntryAction() error = %v", err)
|
||||
}
|
||||
|
||||
u.state.SelectedEntryID = "entry-1"
|
||||
saved, ok := u.selectedEntry()
|
||||
if !ok {
|
||||
t.Fatal("selectedEntry() ok = false, want true for saved generated entry")
|
||||
}
|
||||
if saved.Password != generated {
|
||||
t.Fatalf("saved.Password = %q, want generated password %q", saved.Password, generated)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1765,6 +1748,53 @@ func TestUICopyActionSanitizesClipboardBackendErrors(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestUIGeneratedPasswordFlowsIntoEditEntryForm(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
u := newUIWithModel("desktop", vault.Model{
|
||||
Entries: []vault.Entry{
|
||||
{
|
||||
ID: "vault-console",
|
||||
Title: "Vault Console",
|
||||
Username: "dannyocean",
|
||||
Password: "token-1",
|
||||
URL: "https://vault.crew.example.invalid",
|
||||
Path: []string{"Root", "Internet"},
|
||||
},
|
||||
},
|
||||
})
|
||||
u.showEntriesSection()
|
||||
u.state.NavigateToPath([]string{"Root", "Internet"})
|
||||
u.filter()
|
||||
u.state.SelectedEntryID = "vault-console"
|
||||
u.loadSelectedEntryIntoEditor()
|
||||
u.passwordProfile.SetText("strong")
|
||||
|
||||
if err := u.generatePasswordAction(); err != nil {
|
||||
t.Fatalf("generatePasswordAction() error = %v", err)
|
||||
}
|
||||
|
||||
generated := u.entryPassword.Text()
|
||||
if generated == "token-1" {
|
||||
t.Fatal("entryPassword.Text() = token-1, want a newly generated password")
|
||||
}
|
||||
if len(generated) < passwords.DefaultProfiles()["strong"].Length {
|
||||
t.Fatalf("len(entryPassword.Text()) = %d, want at least %d after generate", len(generated), passwords.DefaultProfiles()["strong"].Length)
|
||||
}
|
||||
|
||||
if err := u.saveEntryAction(); err != nil {
|
||||
t.Fatalf("saveEntryAction() error = %v", err)
|
||||
}
|
||||
|
||||
saved, ok := u.selectedEntry()
|
||||
if !ok {
|
||||
t.Fatal("selectedEntry() ok = false, want true for edited entry")
|
||||
}
|
||||
if saved.Password != generated {
|
||||
t.Fatalf("saved.Password = %q, want generated password %q", saved.Password, generated)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUIPasswordRevealTogglesDisplayedPasswordAndLockResetsIt(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user