package webui import ( "net/http" "net/http/httptest" "net/url" "strconv" "strings" "testing" ) // TestWebmailMessagePaneMarksReadAndReturnsFragment confirms the Outlook-style reading // pane's fetch endpoint returns a bare fragment (no dashboard chrome) containing the // message body, and marks the message read just like opening the full page does. func TestWebmailMessagePaneMarksReadAndReturnsFragment(t *testing.T) { app := newTestApp(t) mux := app.Mux() domains, _ := app.DB.ListDomains() mailboxID := createTestMailboxWithPassword(t, app, "panetest@example.com", domains[0].ID, "panetest-password-1!") cookie := webmailLoginSession(t, app, mailboxID) uid := storeTestMessage(t, app, mailboxID, "INBOX", "a@example.com", "Pane test", "the body of the message") req := httptest.NewRequest(http.MethodGet, MailboxPrefix+"/mail/INBOX/"+strconv.FormatInt(uid, 10)+"/pane", nil) req.AddCookie(cookie) rec := httptest.NewRecorder() mux.ServeHTTP(rec, req) if rec.Code != http.StatusOK { t.Fatalf("expected 200, got %d: %s", rec.Code, rec.Body.String()) } body := rec.Body.String() if !strings.Contains(body, "the body of the message") { t.Errorf("expected the message body in the fragment, got:\n%s", body) } if strings.Contains(body, " POST .../bulk) can delete-to-Trash and mark-read/unread // several messages in one request. func TestWebmailBulkActionDeleteAndMarkRead(t *testing.T) { app := newTestApp(t) mux := app.Mux() domains, _ := app.DB.ListDomains() mailboxID := createTestMailboxWithPassword(t, app, "bulktest@example.com", domains[0].ID, "bulktest-password-1!") cookie := webmailLoginSession(t, app, mailboxID) uid1 := storeTestMessage(t, app, mailboxID, "INBOX", "a@example.com", "One", "body1") uid2 := storeTestMessage(t, app, mailboxID, "INBOX", "b@example.com", "Two", "body2") uid3 := storeTestMessage(t, app, mailboxID, "INBOX", "c@example.com", "Three", "body3") post := func(action string, uids ...int64) *httptest.ResponseRecorder { form := url.Values{"action": {action}} for _, u := range uids { form.Add("uid", strconv.FormatInt(u, 10)) } req := httptest.NewRequest(http.MethodPost, MailboxPrefix+"/mail/INBOX/bulk", strings.NewReader(form.Encode())) req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.AddCookie(cookie) rec := httptest.NewRecorder() mux.ServeHTTP(rec, req) return rec } // Mark uid1 and uid2 read in one bulk request. if rec := post("read", uid1, uid2); rec.Code != http.StatusFound { t.Fatalf("bulk read: status=%d body=%s", rec.Code, rec.Body.String()) } for _, uid := range []int64{uid1, uid2} { msg, err := app.DB.GetMessageByUID(mailboxID, uid) if err != nil { t.Fatal(err) } if isUnread(msg.Flags) { t.Errorf("expected message %d marked read", uid) } } msg3, err := app.DB.GetMessageByUID(mailboxID, uid3) if err != nil { t.Fatal(err) } if !isUnread(msg3.Flags) { t.Error("expected message 3 (not in the bulk request) to remain unread") } // Bulk-delete uid1 and uid3 (uid2 stays in INBOX). if rec := post("delete", uid1, uid3); rec.Code != http.StatusFound { t.Fatalf("bulk delete: status=%d body=%s", rec.Code, rec.Body.String()) } inbox, err := app.DB.ListMessagesInFolder(mailboxID, "INBOX") if err != nil { t.Fatal(err) } if len(inbox) != 1 || inbox[0].ID != uid2 { t.Fatalf("expected only message 2 left in INBOX, got %+v", inbox) } trash, err := app.DB.ListMessagesInFolder(mailboxID, "Trash") if err != nil { t.Fatal(err) } if len(trash) != 2 { t.Fatalf("expected 2 messages in Trash, got %d", len(trash)) } } // TestWebmailBulkActionSkipsUIDFromAnotherFolder confirms a uid that doesn't actually // belong to the requested folder is silently skipped rather than aborting the whole // batch or letting a stale/mismatched selection touch the wrong message. func TestWebmailBulkActionSkipsUIDFromAnotherFolder(t *testing.T) { app := newTestApp(t) mux := app.Mux() domains, _ := app.DB.ListDomains() mailboxID := createTestMailboxWithPassword(t, app, "bulkskiptest@example.com", domains[0].ID, "bulkskiptest-password-1!") cookie := webmailLoginSession(t, app, mailboxID) inboxUID := storeTestMessage(t, app, mailboxID, "INBOX", "a@example.com", "In inbox", "body") sentUID := storeTestMessage(t, app, mailboxID, "Sent", "b@example.com", "In sent", "body") form := url.Values{"action": {"delete"}, "uid": {strconv.FormatInt(inboxUID, 10), strconv.FormatInt(sentUID, 10)}} req := httptest.NewRequest(http.MethodPost, MailboxPrefix+"/mail/INBOX/bulk", strings.NewReader(form.Encode())) req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.AddCookie(cookie) rec := httptest.NewRecorder() mux.ServeHTTP(rec, req) if rec.Code != http.StatusFound { t.Fatalf("status=%d body=%s", rec.Code, rec.Body.String()) } sent, err := app.DB.ListMessagesInFolder(mailboxID, "Sent") if err != nil { t.Fatal(err) } if len(sent) != 1 { t.Fatalf("expected the Sent message untouched (wrong folder for this bulk request), got %d left", len(sent)) } trash, err := app.DB.ListMessagesInFolder(mailboxID, "Trash") if err != nil { t.Fatal(err) } if len(trash) != 1 { t.Fatalf("expected the INBOX message moved to Trash, got %d in Trash", len(trash)) } }