add Medusa Cloud Email provider (#13781)

* add Medusa Cloud Email provider

* move cloud config to project level

* add tests

* Create breezy-flowers-fly.md

* rename medusa_cloud_config to cloud

---------

Co-authored-by: Oli Juhl <59018053+olivermrbl@users.noreply.github.com>
This commit is contained in:
Pedro Guzman
2025-10-27 12:39:32 +01:00
committed by GitHub
parent a9dbd035a5
commit cc2614ded7
11 changed files with 721 additions and 18 deletions

View File

@@ -7,11 +7,11 @@ import {
NotificationEvents,
NotificationStatus,
} from "@medusajs/framework/utils"
import { NotificationModuleService } from "@services"
import {
MockEventBusService,
moduleIntegrationTestRunner,
} from "@medusajs/test-utils"
import { NotificationModuleService } from "@services"
import { resolve } from "path"
let moduleOptions = {

View File

@@ -0,0 +1,168 @@
import { INotificationModuleService } from "@medusajs/framework/types"
import { Modules, NotificationStatus } from "@medusajs/framework/utils"
import { moduleIntegrationTestRunner } from "@medusajs/test-utils"
import { resolve } from "path"
jest.setTimeout(30000)
const successMedusaCloudEmailResponse = {
ok: true,
status: 200,
statusText: "OK",
json: () => Promise.resolve({ id: "external_id_1" }),
}
const testNotification = {
to: "customer@test.com",
template: "some-template",
channel: "email",
data: {
link: "https://test.com",
},
}
moduleIntegrationTestRunner<INotificationModuleService>({
moduleName: Modules.NOTIFICATION,
moduleOptions: {
cloud: {
api_key: "test-api-key",
endpoint: "https://medusacloud.com/emails",
environment_handle: "test-environment",
},
},
testSuite: ({ service }) =>
describe("Medusa Cloud Email provider", () => {
let fetchMock: jest.SpyInstance
beforeEach(() => {
fetchMock = jest
.spyOn(globalThis, "fetch")
.mockImplementation(
async () => successMedusaCloudEmailResponse as any
)
})
afterEach(() => {
fetchMock.mockClear()
})
it("should send email notification to Medusa Cloud", async () => {
const result = await service.createNotifications(testNotification)
expect(result).toEqual(
expect.objectContaining({
provider_id: "cloud",
external_id: "external_id_1",
status: NotificationStatus.SUCCESS,
})
)
const [url, request] = fetchMock.mock.calls[0]
expect(url).toBe("https://medusacloud.com/emails/send")
expect(request.method).toBe("POST")
expect(request.headers["Content-Type"]).toBe("application/json")
expect(request.headers["Authorization"]).toBe("Basic test-api-key")
expect(request.headers["x-medusa-environment-handle"]).toBe(
"test-environment"
)
expect(JSON.parse(request.body)).toEqual({
to: "customer@test.com",
template: "some-template",
data: {
link: "https://test.com",
},
})
})
it("should return an error if the Medusa Cloud Email provider fails", async () => {
fetchMock.mockImplementation(
async () =>
({
ok: false,
status: 500,
statusText: "Internal Server Error",
json: () => Promise.resolve({ message: "Internal Server Error" }),
} as any)
)
await expect(
service.createNotifications(testNotification)
).rejects.toThrow()
})
}),
})
moduleIntegrationTestRunner<INotificationModuleService>({
moduleName: Modules.NOTIFICATION,
moduleOptions: {
cloud: {
api_key: "test-api-key",
endpoint: "https://medusacloud.com/emails",
environment_handle: "test-environment",
},
providers: [
{
resolve: resolve(
process.cwd() +
"/integration-tests/__fixtures__/providers/default-provider"
),
id: "test-provider",
options: {
name: "Test provider",
channels: ["email"],
},
},
],
},
testSuite: ({ service }) =>
describe("Medusa Cloud Email provider - when another email provider is configured", () => {
let fetchMock: jest.SpyInstance
beforeEach(() => {
fetchMock = jest
.spyOn(globalThis, "fetch")
.mockImplementation(
async () => successMedusaCloudEmailResponse as any
)
})
afterEach(() => {
fetchMock.mockClear()
})
it("should not enable Medusa Cloud Email provider", async () => {
const result = await service.createNotifications(testNotification)
expect(result).toMatchObject({ status: NotificationStatus.SUCCESS })
expect(fetchMock).not.toHaveBeenCalled()
})
}),
})
moduleIntegrationTestRunner<INotificationModuleService>({
moduleName: Modules.NOTIFICATION,
moduleOptions: {},
testSuite: ({ service }) =>
describe("Medusa Cloud Email provider - when cloud options are not provided", () => {
let fetchMock: jest.SpyInstance
beforeEach(() => {
fetchMock = jest
.spyOn(globalThis, "fetch")
.mockImplementation(
async () => successMedusaCloudEmailResponse as any
)
})
afterEach(() => {
fetchMock.mockClear()
})
it("should not enable Medusa Cloud Email provider", async () => {
await expect(
service.createNotifications(testNotification)
).rejects.toThrow()
expect(fetchMock).not.toHaveBeenCalled()
})
}),
})