refactor: quality workflow, docs, tests
This commit is contained in:
parent
a9caf36b01
commit
68ace0a858
27 changed files with 758 additions and 330 deletions
|
|
@ -1,19 +1,35 @@
|
|||
import { describe, it, expect, vi, beforeEach } from "vitest"
|
||||
import { describe, it, expect, vi } from "vitest"
|
||||
|
||||
// Mock tls to simulate an SMTP server over implicit TLS
|
||||
let lastWrites: string[] = []
|
||||
vi.mock("tls", () => {
|
||||
type Listener = (...args: unknown[]) => void
|
||||
|
||||
class MockSocket {
|
||||
listeners: Record<string, Function[]> = {}
|
||||
listeners: Record<string, Listener[]> = {}
|
||||
writes: string[] = []
|
||||
// very small state machine of server responses
|
||||
private step = 0
|
||||
on(event: string, cb: Function) {
|
||||
private enqueue(messages: string | string[], type: "data" | "end" = "data") {
|
||||
const chunks = Array.isArray(messages) ? messages : [messages]
|
||||
chunks.forEach((chunk, index) => {
|
||||
const delay = index === 0 ? 0 : 1
|
||||
setTimeout(() => {
|
||||
if (type === "end") {
|
||||
void chunk
|
||||
this.emit("end")
|
||||
return
|
||||
}
|
||||
this.emit("data", Buffer.from(chunk))
|
||||
}, delay)
|
||||
})
|
||||
}
|
||||
on(event: string, cb: Listener) {
|
||||
this.listeners[event] = this.listeners[event] || []
|
||||
this.listeners[event].push(cb)
|
||||
return this
|
||||
}
|
||||
removeListener(event: string, cb: Function) {
|
||||
removeListener(event: string, cb: Listener) {
|
||||
if (!this.listeners[event]) return this
|
||||
this.listeners[event] = this.listeners[event].filter((f) => f !== cb)
|
||||
return this
|
||||
|
|
@ -27,37 +43,36 @@ vi.mock("tls", () => {
|
|||
// Respond depending on client command
|
||||
if (this.step === 0 && line.startsWith("EHLO")) {
|
||||
this.step = 1
|
||||
this.emit("data", Buffer.from("250-local\r\n"))
|
||||
this.emit("data", Buffer.from("250 OK\r\n"))
|
||||
this.enqueue(["250-local\r\n", "250 OK\r\n"])
|
||||
} else if (this.step === 1 && line === "AUTH LOGIN") {
|
||||
this.step = 2
|
||||
this.emit("data", Buffer.from("334 VXNlcm5hbWU6\r\n"))
|
||||
this.enqueue("334 VXNlcm5hbWU6\r\n")
|
||||
} else if (this.step === 2) {
|
||||
this.step = 3
|
||||
this.emit("data", Buffer.from("334 UGFzc3dvcmQ6\r\n"))
|
||||
this.enqueue("334 UGFzc3dvcmQ6\r\n")
|
||||
} else if (this.step === 3) {
|
||||
this.step = 4
|
||||
this.emit("data", Buffer.from("235 Auth OK\r\n"))
|
||||
this.enqueue("235 Auth OK\r\n")
|
||||
} else if (this.step === 4 && line.startsWith("MAIL FROM:")) {
|
||||
this.step = 5
|
||||
this.emit("data", Buffer.from("250 FROM OK\r\n"))
|
||||
this.enqueue("250 FROM OK\r\n")
|
||||
} else if (this.step === 5 && line.startsWith("RCPT TO:")) {
|
||||
this.step = 6
|
||||
this.emit("data", Buffer.from("250 RCPT OK\r\n"))
|
||||
this.enqueue("250 RCPT OK\r\n")
|
||||
} else if (this.step === 6 && line === "DATA") {
|
||||
this.step = 7
|
||||
this.emit("data", Buffer.from("354 End data with <CR><LF>.<CR><LF>\r\n"))
|
||||
this.enqueue("354 End data with <CR><LF>.<CR><LF>\r\n")
|
||||
} else if (this.step === 7 && line.endsWith(".")) {
|
||||
this.step = 8
|
||||
this.emit("data", Buffer.from("250 Queued\r\n"))
|
||||
this.enqueue("250 Queued\r\n")
|
||||
} else if (this.step === 8 && line === "QUIT") {
|
||||
this.emit("end")
|
||||
this.enqueue("", "end")
|
||||
}
|
||||
}
|
||||
end() {}
|
||||
}
|
||||
|
||||
function connect(_port: number, _host: string, _opts: unknown, cb?: Function) {
|
||||
function connect(_port: number, _host: string, _opts: unknown, cb?: () => void) {
|
||||
const socket = new MockSocket()
|
||||
lastWrites = socket.writes
|
||||
// initial server greeting
|
||||
|
|
@ -92,7 +107,7 @@ describe("sendSmtpMail", () => {
|
|||
|
||||
it("extracts envelope address from parentheses or raw email", async () => {
|
||||
const { sendSmtpMail } = await import("@/server/email-smtp")
|
||||
const tlsMock = await import("tls" as any)
|
||||
const tlsMock = (await import("tls")) as unknown as { __getLastWrites: () => string[] }
|
||||
await sendSmtpMail(
|
||||
{
|
||||
host: "smtp.mock",
|
||||
|
|
@ -105,7 +120,7 @@ describe("sendSmtpMail", () => {
|
|||
"Subject",
|
||||
"<p>Hi</p>"
|
||||
)
|
||||
const writes = (tlsMock as any).__getLastWrites() as string[]
|
||||
const writes = tlsMock.__getLastWrites()
|
||||
expect(writes.some((w) => /MAIL FROM:<chat@esdrasrenan.com.br>\r\n/.test(w))).toBe(true)
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { describe, expect, it } from "vitest"
|
||||
import { dateKeyTZ, getTZParts, isAtHourTZ } from "@/lib/time"
|
||||
import { dateKeyTZ, isAtHourTZ } from "@/lib/time"
|
||||
|
||||
describe("time tz helpers", () => {
|
||||
it("computes date key in timezone", () => {
|
||||
|
|
@ -14,4 +14,3 @@ describe("time tz helpers", () => {
|
|||
expect(isAtHourTZ(d, "America/Sao_Paulo", 8)).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue