You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
123 lines
3.7 KiB
123 lines
3.7 KiB
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
import { resetEnvCache } from "@/lib/env";
|
|
import {
|
|
createImapClientFromConfig,
|
|
ImapClient,
|
|
type ImapClientConfig,
|
|
} from "@/services/imap/client";
|
|
import {
|
|
getMockMailServer,
|
|
resetMockMailServer,
|
|
} from "@/services/imap/mock-mail-server";
|
|
|
|
const BASE_CONFIG: ImapClientConfig = {
|
|
host: "mock.local",
|
|
port: 993,
|
|
user: "test@mock.local",
|
|
pass: "test",
|
|
connectTimeoutMs: 1000,
|
|
readTimeoutMs: 1000,
|
|
folder: "INBOX",
|
|
};
|
|
|
|
function enableTestMode() {
|
|
process.env.DATABASE_URL =
|
|
process.env.DATABASE_URL || "mysql://app:app@localhost:7023/email_forecast";
|
|
process.env.TEST_MODE = "1";
|
|
resetEnvCache();
|
|
resetMockMailServer();
|
|
}
|
|
|
|
function disableTestMode() {
|
|
delete process.env.TEST_MODE;
|
|
resetEnvCache();
|
|
resetMockMailServer();
|
|
}
|
|
|
|
describe("MockMailServer", () => {
|
|
beforeEach(() => {
|
|
process.env.DATABASE_URL =
|
|
process.env.DATABASE_URL || "mysql://app:app@localhost:7023/email_forecast";
|
|
disableTestMode();
|
|
});
|
|
|
|
afterEach(() => {
|
|
disableTestMode();
|
|
});
|
|
|
|
it("injects eml with attachment and fetches by uid", async () => {
|
|
const server = getMockMailServer();
|
|
const injected = server.inject({
|
|
from: "ops@example.com",
|
|
subject: "预报 WHSU8127240",
|
|
text: "请查收新增预报",
|
|
attachments: [
|
|
{
|
|
filename: "数据模版.xlsx",
|
|
contentType:
|
|
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
content: Buffer.from("xlsx-bytes"),
|
|
},
|
|
],
|
|
});
|
|
const client = server.createClient(BASE_CONFIG);
|
|
await client.connect();
|
|
const uids = await client.searchSince(new Date(0));
|
|
expect(uids).toEqual([injected.uid]);
|
|
const fetched = await client.fetchByUids(uids);
|
|
expect(fetched).toHaveLength(1);
|
|
expect(fetched[0].source.includes("数据模版.xlsx")).toBe(true);
|
|
expect(fetched[0].envelope?.subject).toBe("预报 WHSU8127240");
|
|
await client.disconnect();
|
|
});
|
|
|
|
it("simulates auth failure", async () => {
|
|
const server = getMockMailServer();
|
|
server.setFault("auth_fail");
|
|
const client = server.createClient(BASE_CONFIG);
|
|
await expect(client.connect()).rejects.toThrow(/AUTHENTICATIONFAILED/);
|
|
});
|
|
|
|
it("simulates connect timeout", async () => {
|
|
const server = getMockMailServer();
|
|
server.setFault("timeout");
|
|
const client = server.createClient(BASE_CONFIG);
|
|
await expect(client.connect()).rejects.toMatchObject({ code: "ETIMEOUT" });
|
|
});
|
|
|
|
it("simulates empty mailbox", async () => {
|
|
const server = getMockMailServer();
|
|
server.inject({ subject: "hidden", text: "x" });
|
|
server.setFault("empty");
|
|
const client = server.createClient(BASE_CONFIG);
|
|
await client.connect();
|
|
expect(await client.searchSince(new Date(0))).toEqual([]);
|
|
expect(await client.countUnseen()).toBe(0);
|
|
});
|
|
});
|
|
|
|
describe("IMAP factory TEST_MODE", () => {
|
|
afterEach(() => {
|
|
disableTestMode();
|
|
});
|
|
|
|
it("returns real ImapClient when TEST_MODE is off", () => {
|
|
process.env.DATABASE_URL =
|
|
process.env.DATABASE_URL || "mysql://app:app@localhost:7023/email_forecast";
|
|
delete process.env.TEST_MODE;
|
|
resetEnvCache();
|
|
const client = createImapClientFromConfig(BASE_CONFIG);
|
|
expect(client).toBeInstanceOf(ImapClient);
|
|
});
|
|
|
|
it("returns MockMailServer client when TEST_MODE=1", async () => {
|
|
enableTestMode();
|
|
getMockMailServer().inject({ subject: "fixture-a", text: "body" });
|
|
const client = createImapClientFromConfig(BASE_CONFIG);
|
|
expect(client).not.toBeInstanceOf(ImapClient);
|
|
await client.connect();
|
|
const uids = await client.searchSince(new Date(0));
|
|
expect(uids.length).toBe(1);
|
|
});
|
|
});
|