diff --git a/internal/ui/compose_test.go b/internal/ui/compose_test.go index 6d334dd..10f6961 100644 --- a/internal/ui/compose_test.go +++ b/internal/ui/compose_test.go @@ -86,7 +86,8 @@ func TestComposeSuggestions_MultiRecipientInsert(t *testing.T) { // Sending must persist user-typed "Name " recipients into the contacts // store so autocomplete knows them next time (no contacts file needed). func TestHarvestTypedRecipients(t *testing.T) { - s := contacts.Load(filepath.Join(t.TempDir(), "contacts")) + cachePath := filepath.Join(t.TempDir(), "contacts") + s := contacts.Load(cachePath) m := Model{contacts: s} m.harvestTypedRecipients( "Max Muster , bare@x.io", @@ -109,4 +110,8 @@ func TestHarvestTypedRecipients(t *testing.T) { // Nil store: must be a no-op, not a panic. nilModel := Model{} nilModel.harvestTypedRecipients("A ") + + // harvestTypedRecipients persists via safeGo(SaveIfDirty) — wait for + // the write before TempDir cleanup runs. + waitForFile(t, cachePath) } diff --git a/internal/ui/helpers_test.go b/internal/ui/helpers_test.go new file mode 100644 index 0000000..0af3dd4 --- /dev/null +++ b/internal/ui/helpers_test.go @@ -0,0 +1,25 @@ +package ui + +import ( + "os" + "testing" + "time" +) + +// waitForFile blocks until path exists on disk. Tests that trigger async +// persistence (safeGo → Save) into a t.TempDir must call this before +// returning: the test's TempDir cleanup otherwise races the goroutine and +// fails with "unlinkat … directory not empty" (flaky under -count / -race). +func waitForFile(t *testing.T, path string) { + t.Helper() + deadline := time.Now().Add(2 * time.Second) + for { + if _, err := os.Stat(path); err == nil { + return + } + if !time.Now().Before(deadline) { + t.Fatalf("%s never landed on disk", path) + } + time.Sleep(2 * time.Millisecond) + } +} diff --git a/internal/ui/model_test.go b/internal/ui/model_test.go index 45fc3a8..b3e9390 100644 --- a/internal/ui/model_test.go +++ b/internal/ui/model_test.go @@ -1300,6 +1300,9 @@ func TestApplySenderRules_PersistsMatches(t *testing.T) { if n := m.applySenderRules(emails); n != 1 { t.Errorf("applySenderRules = %d, want 1", n) } + // applySenderRules persists via safeGo(store.Save) — wait for the + // write before TempDir cleanup runs. + waitForFile(t, path) if title, ok := s.TitleOf(""); !ok || title != "Bounces" { t.Errorf(" should now belong to Bounces, got %q %v", title, ok) }