chore: Treat internal event differently, primarely do not display info logs for those events (#8767)

* chore: Treat internal event differently, primarely do not display info log for those events

* revert doc

* add few tests

* only set internal option if present

* revert to previous condition

* start including feedback after discussion

* include feedback

* fix modules integration tests

* fix modules integration tests

* fix event bus local
This commit is contained in:
Adrien de Peretti authored and GitHub committed 2024-08-28 16:46:40 +02:00
1 parent 6cfe9bd874
commit 5bec38538a
27 files changed
+915 -465

No files matched your search

@@ -21,6 +21,11 @@ export type SharedContext = {
export interface MessageAggregatorFormat { export interface MessageAggregatorFormat {
groupBy?: string[] groupBy?: string[]
sortBy?: { [key: string]: string[] | string | number } sortBy?: { [key: string]: string[] | string | number }
/**
* @internal
* will prevent the info log to be displayed about those events
*/
internal?: boolean
} }
export interface IMessageAggregator { export interface IMessageAggregator {
@@ -50,7 +50,7 @@ export class MessageAggregator implements IMessageAggregator {
this.save(composedMessages) this.save(composedMessages)
} }
getMessages(format?: MessageAggregatorFormat): { getMessages(format: MessageAggregatorFormat = {}): {
[group: string]: Message[] [group: string]: Message[]
} { } {
const { groupBy, sortBy } = format ?? {} const { groupBy, sortBy } = format ?? {}
@@ -78,6 +78,15 @@ export class MessageAggregator implements IMessageAggregator {
messages = groupedMessages messages = groupedMessages
} }
if (format.internal) {
Object.values(messages).forEach((group) => {
group.forEach((msg) => {
msg.options = msg.options ?? {}
msg.options.internal = format.internal
})
})
}
return messages return messages
} }
@@ -0,0 +1,96 @@
import { EmitEvents } from "../emit-events"
import { MedusaContext } from "../context-parameter"
import { Context } from "@medusajs/types"
import { InjectSharedContext } from "../inject-shared-context"
describe("EmitEvents", () => {
it(`should call the emit event method from the base service including the messages and their options`, async () => {
const mock = jest.fn()
class FakeService {
async emitEvents_(...args) {
return mock(...args)
}
@InjectSharedContext()
@EmitEvents({ internal: true })
async method(@MedusaContext() sharedContext: Context = {}) {
sharedContext.messageAggregator?.saveRawMessageData({
data: { id: 1 },
object: "test",
action: "create",
source: "test",
eventName: "test-event",
})
}
}
const service = new FakeService()
await service.method()
expect(mock).toHaveBeenCalledTimes(1)
expect(mock).toHaveBeenCalledWith({
default: [
{
name: "test-event",
metadata: {
source: "test",
object: "test",
action: "create",
},
data: {
id: 1,
},
options: {
internal: true,
},
},
],
})
})
it(`should call the emit event method from the base service with grouped messages`, async () => {
const mock = jest.fn()
class FakeService {
async emitEvents_(...args) {
return mock(...args)
}
@InjectSharedContext()
@EmitEvents({ internal: true, groupBy: ["name"] })
async method(@MedusaContext() sharedContext: Context = {}) {
sharedContext.messageAggregator?.saveRawMessageData({
data: { id: 1 },
object: "test",
action: "create",
source: "test",
eventName: "test-event",
})
}
}
const service = new FakeService()
await service.method()
expect(mock).toHaveBeenCalledTimes(1)
expect(mock).toHaveBeenCalledWith({
"test-event": [
{
name: "test-event",
metadata: {
source: "test",
object: "test",
action: "create",
},
data: {
id: 1,
},
options: {
internal: true,
},
},
],
})
})
})
@@ -2,6 +2,12 @@ import { MessageAggregator } from "../../event-bus"
import { InjectIntoContext } from "./inject-into-context" import { InjectIntoContext } from "./inject-into-context"
import { MessageAggregatorFormat } from "@medusajs/types" import { MessageAggregatorFormat } from "@medusajs/types"
/**
* @internal this decorator is not meant to be used except by the internal team for now
*
* @param options
* @constructor
*/
export function EmitEvents( export function EmitEvents(
options: MessageAggregatorFormat = {} as MessageAggregatorFormat options: MessageAggregatorFormat = {} as MessageAggregatorFormat
) { ) {
@@ -11,11 +11,11 @@ import {
SoftDeleteReturn, SoftDeleteReturn,
} from "@medusajs/types" } from "@medusajs/types"
import { import {
MapToConfig,
isString, isString,
kebabCase, kebabCase,
lowerCaseFirst, lowerCaseFirst,
mapObjectTo, mapObjectTo,
MapToConfig,
pluralize, pluralize,
upperCaseFirst, upperCaseFirst,
} from "../common" } from "../common"
@@ -271,7 +271,10 @@ export function MedusaService<
? { id: primaryKeyValue } ? { id: primaryKeyValue }
: primaryKeyValue, : primaryKeyValue,
metadata: { source: "", action: "", object: "" }, metadata: { source: "", action: "", object: "" },
})) })),
{
internal: true,
}
) )
} }
@@ -302,7 +305,10 @@ export function MedusaService<
name: `${kebabCase(modelName)}.deleted`, name: `${kebabCase(modelName)}.deleted`,
metadata: { source: "", action: "", object: "" }, metadata: { source: "", action: "", object: "" },
data: { id }, data: { id },
})) })),
{
internal: true,
}
) )
// Map internal table/column names to their respective external linkable keys // Map internal table/column names to their respective external linkable keys
@@ -392,6 +398,11 @@ export function MedusaService<
) )
} }
/**
* @internal this method is not meant to be used except by the internal team for now
* @param groupedEvents
* @protected
*/
protected async emitEvents_(groupedEvents) { protected async emitEvents_(groupedEvents) {
if (!this.eventBusModuleService_ || !groupedEvents) { if (!this.eventBusModuleService_ || !groupedEvents) {
return return
@@ -399,7 +410,11 @@ export function MedusaService<
const promises: Promise<void>[] = [] const promises: Promise<void>[] = []
for (const group of Object.keys(groupedEvents)) { for (const group of Object.keys(groupedEvents)) {
promises.push(this.eventBusModuleService_.emit(groupedEvents[group])) promises.push(
this.eventBusModuleService_.emit(groupedEvents[group], {
internal: true,
})
)
} }
await Promise.all(promises) await Promise.all(promises)
@@ -39,6 +39,49 @@ describe("LocalEventBusService", () => {
data: { hi: "1234" }, data: { hi: "1234" },
name: "eventName", name: "eventName",
}) })
expect(loggerMock.info).toHaveBeenCalledTimes(1)
expect(loggerMock.info).toHaveBeenCalledWith(
"Processing eventName which has undefined subscribers"
)
})
it("should emit an event but not log anything if it is internal", async () => {
eventEmitter.emit = jest.fn((data) => data)
await eventBus.emit({
name: "eventName",
data: { hi: "1234" },
options: {
internal: true,
},
})
expect(eventEmitter.emit).toHaveBeenCalledTimes(1)
expect(eventEmitter.emit).toHaveBeenCalledWith("eventName", {
data: { hi: "1234" },
name: "eventName",
})
expect(loggerMock.info).toHaveBeenCalledTimes(0)
await eventBus.emit(
{
name: "eventName",
data: { hi: "1234" },
},
{
internal: true,
}
)
expect(eventEmitter.emit).toHaveBeenCalledTimes(2)
expect(eventEmitter.emit).toHaveBeenCalledWith("eventName", {
data: { hi: "1234" },
name: "eventName",
})
expect(loggerMock.info).toHaveBeenCalledTimes(0)
}) })
it("should emit multiple events", async () => { it("should emit multiple events", async () => {
@@ -87,7 +130,7 @@ describe("LocalEventBusService", () => {
groupEventFn = jest.spyOn(eventBus, "groupEvent" as any) groupEventFn = jest.spyOn(eventBus, "groupEvent" as any)
eventEmitter.emit = jest.fn((data) => data) eventEmitter.emit = jest.fn((data) => data)
eventBus.emit([ await eventBus.emit([
{ {
name: "test-event", name: "test-event",
data: { test: "1234" }, data: { test: "1234" },
@@ -201,12 +244,12 @@ describe("LocalEventBusService", () => {
expect(getMap().get("group-1")).toHaveLength(1) expect(getMap().get("group-1")).toHaveLength(1)
expect(getMap().get("group-2")).toHaveLength(1) expect(getMap().get("group-2")).toHaveLength(1)
eventBus.clearGroupedEvents("group-1") await eventBus.clearGroupedEvents("group-1")
expect(getMap().get("group-1")).not.toBeDefined() expect(getMap().get("group-1")).not.toBeDefined()
expect(getMap().get("group-2")).toHaveLength(1) expect(getMap().get("group-2")).toHaveLength(1)
eventBus.clearGroupedEvents("group-2") await eventBus.clearGroupedEvents("group-2")
expect(getMap().get("group-2")).not.toBeDefined() expect(getMap().get("group-2")).not.toBeDefined()
}) })
@@ -35,6 +35,12 @@ export default class LocalEventBusService extends AbstractEventBusModuleService
this.groupedEventsMap_ = new Map() this.groupedEventsMap_ = new Map()
} }
/**
* Accept an event name and some options
*
* @param eventsData
* @param options The options can include `internal` which will prevent the event from being logged
*/
async emit<T = unknown>( async emit<T = unknown>(
eventsData: Message<T> | Message<T>[], eventsData: Message<T> | Message<T>[],
options: Record<string, unknown> = {} options: Record<string, unknown> = {}
@@ -48,9 +54,11 @@ export default class LocalEventBusService extends AbstractEventBusModuleService
eventData.name eventData.name
) )
this.logger_?.info( if (!options.internal && !eventData.options?.internal) {
`Processing ${eventData.name} which has ${eventListenersCount} subscribers` this.logger_?.info(
) `Processing ${eventData.name} which has ${eventListenersCount} subscribers`
)
}
if (eventListenersCount === 0) { if (eventListenersCount === 0) {
continue continue
@@ -98,7 +106,7 @@ export default class LocalEventBusService extends AbstractEventBusModuleService
this.eventEmitter_.emit(event.name, eventBody) this.eventEmitter_.emit(event.name, eventBody)
} }
this.clearGroupedEvents(eventGroupId) await this.clearGroupedEvents(eventGroupId)
} }
async clearGroupedEvents(eventGroupId: string) { async clearGroupedEvents(eventGroupId: string) {
@@ -307,6 +307,8 @@ describe("RedisEventBusService", () => {
JSON.stringify(testGroup2Event2), JSON.stringify(testGroup2Event2),
]) ])
} }
return
}) })
queue = (eventBus as any).queue_ queue = (eventBus as any).queue_
@@ -337,7 +339,7 @@ describe("RedisEventBusService", () => {
}) })
describe("worker_", () => { describe("worker_", () => {
let result let result!: any
describe("Successfully processes the jobs", () => { describe("Successfully processes the jobs", () => {
beforeEach(async () => { beforeEach(async () => {
@@ -421,12 +423,16 @@ describe("RedisEventBusService", () => {
}) })
it("should retry processing when subcribers fail, if configured - final attempt", async () => { it("should retry processing when subcribers fail, if configured - final attempt", async () => {
eventBus.subscribe("eventName", async () => Promise.resolve(), { eventBus.subscribe("eventName", async () => await Promise.resolve(), {
subscriberId: "1", subscriberId: "1",
}) })
eventBus.subscribe("eventName", async () => Promise.reject("fail1"), { eventBus.subscribe(
subscriberId: "2", "eventName",
}) async () => await Promise.reject("fail1"),
{
subscriberId: "2",
}
)
result = await eventBus result = await eventBus
.worker_({ .worker_({
@@ -456,12 +462,16 @@ describe("RedisEventBusService", () => {
}) })
it("should retry processing when subcribers fail, if configured", async () => { it("should retry processing when subcribers fail, if configured", async () => {
eventBus.subscribe("eventName", async () => Promise.resolve(), { eventBus.subscribe("eventName", async () => await Promise.resolve(), {
subscriberId: "1", subscriberId: "1",
}) })
eventBus.subscribe("eventName", async () => Promise.reject("fail1"), { eventBus.subscribe(
subscriberId: "2", "eventName",
}) async () => await Promise.reject("fail1"),
{
subscriberId: "2",
}
)
result = await eventBus result = await eventBus
.worker_({ .worker_({
@@ -11,7 +11,7 @@ import {
} from "@medusajs/utils" } from "@medusajs/utils"
import { BulkJobOptions, Queue, Worker } from "bullmq" import { BulkJobOptions, Queue, Worker } from "bullmq"
import { Redis } from "ioredis" import { Redis } from "ioredis"
import { BullJob, EventBusRedisModuleOptions } from "../types" import { BullJob, EventBusRedisModuleOptions, Options } from "../types"
type InjectedDependencies = { type InjectedDependencies = {
logger: Logger logger: Logger
@@ -87,7 +87,7 @@ export default class RedisEventBusService extends AbstractEventBusModuleService
private buildEvents<T>( private buildEvents<T>(
eventsData: Message<T>[], eventsData: Message<T>[],
options: BulkJobOptions = {} options: Options = {}
): IORedisEventType<T>[] { ): IORedisEventType<T>[] {
const opts = { const opts = {
// default options // default options
@@ -127,7 +127,7 @@ export default class RedisEventBusService extends AbstractEventBusModuleService
*/ */
async emit<T = unknown>( async emit<T = unknown>(
eventsData: Message<T> | Message<T>[], eventsData: Message<T> | Message<T>[],
options: BulkJobOptions & { groupedEventsTTL?: number } = {} options: Options = {}
): Promise<void> { ): Promise<void> {
let eventsDataArray = Array.isArray(eventsData) ? eventsData : [eventsData] let eventsDataArray = Array.isArray(eventsData) ? eventsData : [eventsData]
@@ -169,7 +169,7 @@ export default class RedisEventBusService extends AbstractEventBusModuleService
// This will be helpful in preventing stale data from staying in redis for too long // This will be helpful in preventing stale data from staying in redis for too long
// in the event the module fails to cleanup events. For long running workflows, setting a much higher // in the event the module fails to cleanup events. For long running workflows, setting a much higher
// TTL or even skipping the TTL would be required // TTL or even skipping the TTL would be required
this.setExpire(groupId, groupedEventsTTL) void this.setExpire(groupId, groupedEventsTTL)
const eventsData = this.buildEvents(events, options) const eventsData = this.buildEvents(events, options)
@@ -229,7 +229,7 @@ export default class RedisEventBusService extends AbstractEventBusModuleService
* @return resolves to the results of the subscriber calls. * @return resolves to the results of the subscriber calls.
*/ */
worker_ = async <T>(job: BullJob<T>): Promise<unknown> => { worker_ = async <T>(job: BullJob<T>): Promise<unknown> => {
const { data, name } = job const { data, name, opts } = job
const eventSubscribers = this.eventToSubscribersMap.get(name) || [] const eventSubscribers = this.eventToSubscribersMap.get(name) || []
const wildcardSubscribers = this.eventToSubscribersMap.get("*") || [] const wildcardSubscribers = this.eventToSubscribersMap.get("*") || []
@@ -250,18 +250,20 @@ export default class RedisEventBusService extends AbstractEventBusModuleService
const isFinalAttempt = currentAttempt === configuredAttempts const isFinalAttempt = currentAttempt === configuredAttempts
if (isRetry) { if (!opts.internal) {
if (isFinalAttempt) { if (isRetry) {
this.logger_.info(`Final retry attempt for ${name}`) if (isFinalAttempt) {
} this.logger_.info(`Final retry attempt for ${name}`)
}
this.logger_.info( this.logger_.info(
`Retrying ${name} which has ${eventSubscribers.length} subscribers (${subscribersInCurrentAttempt.length} of them failed)` `Retrying ${name} which has ${eventSubscribers.length} subscribers (${subscribersInCurrentAttempt.length} of them failed)`
) )
} else { } else {
this.logger_.info( this.logger_.info(
`Processing ${name} which has ${eventSubscribers.length} subscribers` `Processing ${name} which has ${eventSubscribers.length} subscribers`
) )
}
} }
const completedSubscribersInCurrentAttempt: string[] = [] const completedSubscribersInCurrentAttempt: string[] = []
@@ -315,7 +317,7 @@ export default class RedisEventBusService extends AbstractEventBusModuleService
this.logger_.warn(errorMessage) this.logger_.warn(errorMessage)
return Promise.reject(Error(errorMessage)) throw Error(errorMessage)
} }
if (didSubscribersFail && !isFinalAttempt) { if (didSubscribersFail && !isFinalAttempt) {
@@ -325,6 +327,6 @@ export default class RedisEventBusService extends AbstractEventBusModuleService
) )
} }
return Promise.resolve(subscribersResult) return subscribersResult
} }
} }
@@ -1,4 +1,10 @@
import { Job, JobsOptions, QueueOptions, WorkerOptions } from "bullmq" import {
BulkJobOptions,
Job,
JobsOptions,
QueueOptions,
WorkerOptions,
} from "bullmq"
import { RedisOptions } from "ioredis" import { RedisOptions } from "ioredis"
export type JobData<T> = { export type JobData<T> = {
@@ -7,8 +13,14 @@ export type JobData<T> = {
completedSubscriberIds?: string[] | undefined completedSubscriberIds?: string[] | undefined
} }
export type Options = BulkJobOptions & {
groupedEventsTTL?: number
internal?: boolean
}
export type BullJob<T> = { export type BullJob<T> = {
data: JobData<T> data: JobData<T>
opts: Job["opts"] & Options
} & Job } & Job
export type EmitOptions = JobsOptions export type EmitOptions = JobsOptions
@@ -167,14 +167,19 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
}) })
) )
expect(eventBusEmitSpy).toHaveBeenCalledWith([ expect(eventBusEmitSpy).toHaveBeenCalledWith(
buildExpectedEventMessageShape({ [
eventName: FulfillmentEvents.FULFILLMENT_SET_CREATED, buildExpectedEventMessageShape({
action: "created", eventName: FulfillmentEvents.FULFILLMENT_SET_CREATED,
object: "fulfillment_set", action: "created",
data: { id: fulfillmentSet.id }, object: "fulfillment_set",
}), data: { id: fulfillmentSet.id },
]) }),
],
{
internal: true,
}
)
}) })
it("should create a collection of fulfillment sets", async function () { it("should create a collection of fulfillment sets", async function () {
@@ -211,7 +216,10 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
object: "fulfillment_set", object: "fulfillment_set",
data: { id: fulfillmentSets[i].id }, data: { id: fulfillmentSets[i].id },
}), }),
]) ]),
{
internal: true,
}
) )
++i ++i
@@ -245,20 +253,25 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
}) })
) )
expect(eventBusEmitSpy).toHaveBeenCalledWith([ expect(eventBusEmitSpy).toHaveBeenCalledWith(
buildExpectedEventMessageShape({ [
eventName: FulfillmentEvents.FULFILLMENT_SET_CREATED, buildExpectedEventMessageShape({
action: "created", eventName: FulfillmentEvents.FULFILLMENT_SET_CREATED,
object: "fulfillment_set", action: "created",
data: { id: fulfillmentSet.id }, object: "fulfillment_set",
}), data: { id: fulfillmentSet.id },
buildExpectedEventMessageShape({ }),
eventName: FulfillmentEvents.SERVICE_ZONE_CREATED, buildExpectedEventMessageShape({
action: "created", eventName: FulfillmentEvents.SERVICE_ZONE_CREATED,
object: "service_zone", action: "created",
data: { id: fulfillmentSet.service_zones[0].id }, object: "service_zone",
}), data: { id: fulfillmentSet.service_zones[0].id },
]) }),
],
{
internal: true,
}
)
}) })
it("should create a collection of fulfillment sets with new service zones", async function () { it("should create a collection of fulfillment sets with new service zones", async function () {
@@ -326,7 +339,10 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
object: "service_zone", object: "service_zone",
data: { id: fulfillmentSets[i].service_zones[0].id }, data: { id: fulfillmentSets[i].service_zones[0].id },
}), }),
]) ]),
{
internal: true,
}
) )
++i ++i
@@ -373,26 +389,31 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
}) })
) )
expect(eventBusEmitSpy).toHaveBeenCalledWith([ expect(eventBusEmitSpy).toHaveBeenCalledWith(
buildExpectedEventMessageShape({ [
eventName: FulfillmentEvents.FULFILLMENT_SET_CREATED, buildExpectedEventMessageShape({
action: "created", eventName: FulfillmentEvents.FULFILLMENT_SET_CREATED,
object: "fulfillment_set", action: "created",
data: { id: fulfillmentSet.id }, object: "fulfillment_set",
}), data: { id: fulfillmentSet.id },
buildExpectedEventMessageShape({ }),
eventName: FulfillmentEvents.SERVICE_ZONE_CREATED, buildExpectedEventMessageShape({
action: "created", eventName: FulfillmentEvents.SERVICE_ZONE_CREATED,
object: "service_zone", action: "created",
data: { id: fulfillmentSet.service_zones[0].id }, object: "service_zone",
}), data: { id: fulfillmentSet.service_zones[0].id },
buildExpectedEventMessageShape({ }),
eventName: FulfillmentEvents.GEO_ZONE_CREATED, buildExpectedEventMessageShape({
action: "created", eventName: FulfillmentEvents.GEO_ZONE_CREATED,
object: "geo_zone", action: "created",
data: { id: fulfillmentSet.service_zones[0].geo_zones[0].id }, object: "geo_zone",
}), data: { id: fulfillmentSet.service_zones[0].geo_zones[0].id },
]) }),
],
{
internal: true,
}
)
}) })
it("should create a collection of fulfillment sets with new service zones and new geo zones", async function () { it("should create a collection of fulfillment sets with new service zones and new geo zones", async function () {
@@ -496,7 +517,10 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
id: fulfillmentSets[i].service_zones[0].geo_zones[0].id, id: fulfillmentSets[i].service_zones[0].geo_zones[0].id,
}, },
}), }),
]) ]),
{
internal: true,
}
) )
++i ++i
@@ -633,14 +657,19 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
}) })
) )
expect(eventBusEmitSpy).toHaveBeenCalledWith([ expect(eventBusEmitSpy).toHaveBeenCalledWith(
buildExpectedEventMessageShape({ [
eventName: FulfillmentEvents.FULFILLMENT_SET_UPDATED, buildExpectedEventMessageShape({
action: "updated", eventName: FulfillmentEvents.FULFILLMENT_SET_UPDATED,
object: "fulfillment_set", action: "updated",
data: { id: updatedFulfillmentSets.id }, object: "fulfillment_set",
}), data: { id: updatedFulfillmentSets.id },
]) }),
],
{
internal: true,
}
)
}) })
it("should update a collection of fulfillment sets", async function () { it("should update a collection of fulfillment sets", async function () {
@@ -698,7 +727,10 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
object: "fulfillment_set", object: "fulfillment_set",
data: { id: currentFullfillmentSet.id }, data: { id: currentFullfillmentSet.id },
}), }),
]) ]),
{
internal: true,
}
) )
} }
}) })
@@ -816,7 +848,10 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
id: createdFulfillmentSet.service_zones[0].geo_zones[0].id, id: createdFulfillmentSet.service_zones[0].geo_zones[0].id,
}, },
}), }),
]) ]),
{
internal: true,
}
) )
}) })
@@ -920,7 +955,10 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
id: createdServiceZone.geo_zones[0].id, id: createdServiceZone.geo_zones[0].id,
}, },
}), }),
]) ]),
{
internal: true,
}
) )
}) })
@@ -1087,7 +1125,10 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
.id, .id,
}, },
}), }),
]) ]),
{
internal: true,
}
) )
} }
@@ -1230,7 +1271,10 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
id: createdServiceZone.geo_zones[0].id, id: createdServiceZone.geo_zones[0].id,
}, },
}), }),
]) ]),
{
internal: true,
}
) )
} }
@@ -153,32 +153,37 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
) )
expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(4) expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(4)
expect(eventBusEmitSpy).toHaveBeenCalledWith([ expect(eventBusEmitSpy).toHaveBeenCalledWith(
buildExpectedEventMessageShape({ [
eventName: FulfillmentEvents.FULFILLMENT_CREATED, buildExpectedEventMessageShape({
action: "created", eventName: FulfillmentEvents.FULFILLMENT_CREATED,
object: "fulfillment", action: "created",
data: { id: fulfillment.id }, object: "fulfillment",
}), data: { id: fulfillment.id },
buildExpectedEventMessageShape({ }),
eventName: FulfillmentEvents.FULFILLMENT_ADDRESS_CREATED, buildExpectedEventMessageShape({
action: "created", eventName: FulfillmentEvents.FULFILLMENT_ADDRESS_CREATED,
object: "fulfillment_address", action: "created",
data: { id: fulfillment.delivery_address.id }, object: "fulfillment_address",
}), data: { id: fulfillment.delivery_address.id },
buildExpectedEventMessageShape({ }),
eventName: FulfillmentEvents.FULFILLMENT_ITEM_CREATED, buildExpectedEventMessageShape({
action: "created", eventName: FulfillmentEvents.FULFILLMENT_ITEM_CREATED,
object: "fulfillment_item", action: "created",
data: { id: fulfillment.items[0].id }, object: "fulfillment_item",
}), data: { id: fulfillment.items[0].id },
buildExpectedEventMessageShape({ }),
eventName: FulfillmentEvents.FULFILLMENT_LABEL_CREATED, buildExpectedEventMessageShape({
action: "created", eventName: FulfillmentEvents.FULFILLMENT_LABEL_CREATED,
object: "fulfillment_label", action: "created",
data: { id: fulfillment.labels[0].id }, object: "fulfillment_label",
}), data: { id: fulfillment.labels[0].id },
]) }),
],
{
internal: true,
}
)
}) })
it("should create a return fulfillment", async () => { it("should create a return fulfillment", async () => {
@@ -240,32 +245,37 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
) )
expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(4) expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(4)
expect(eventBusEmitSpy).toHaveBeenCalledWith([ expect(eventBusEmitSpy).toHaveBeenCalledWith(
buildExpectedEventMessageShape({ [
eventName: FulfillmentEvents.FULFILLMENT_CREATED, buildExpectedEventMessageShape({
action: "created", eventName: FulfillmentEvents.FULFILLMENT_CREATED,
object: "fulfillment", action: "created",
data: { id: fulfillment.id }, object: "fulfillment",
}), data: { id: fulfillment.id },
buildExpectedEventMessageShape({ }),
eventName: FulfillmentEvents.FULFILLMENT_ADDRESS_CREATED, buildExpectedEventMessageShape({
action: "created", eventName: FulfillmentEvents.FULFILLMENT_ADDRESS_CREATED,
object: "fulfillment_address", action: "created",
data: { id: fulfillment.delivery_address.id }, object: "fulfillment_address",
}), data: { id: fulfillment.delivery_address.id },
buildExpectedEventMessageShape({ }),
eventName: FulfillmentEvents.FULFILLMENT_ITEM_CREATED, buildExpectedEventMessageShape({
action: "created", eventName: FulfillmentEvents.FULFILLMENT_ITEM_CREATED,
object: "fulfillment_item", action: "created",
data: { id: fulfillment.items[0].id }, object: "fulfillment_item",
}), data: { id: fulfillment.items[0].id },
buildExpectedEventMessageShape({ }),
eventName: FulfillmentEvents.FULFILLMENT_LABEL_CREATED, buildExpectedEventMessageShape({
action: "created", eventName: FulfillmentEvents.FULFILLMENT_LABEL_CREATED,
object: "fulfillment_label", action: "created",
data: { id: fulfillment.labels[0].id }, object: "fulfillment_label",
}), data: { id: fulfillment.labels[0].id },
]) }),
],
{
internal: true,
}
)
}) })
}) })
@@ -374,32 +384,37 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
) )
expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(4) expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(4)
expect(eventBusEmitSpy).toHaveBeenCalledWith([ expect(eventBusEmitSpy).toHaveBeenCalledWith(
buildExpectedEventMessageShape({ [
eventName: FulfillmentEvents.FULFILLMENT_UPDATED, buildExpectedEventMessageShape({
action: "updated", eventName: FulfillmentEvents.FULFILLMENT_UPDATED,
object: "fulfillment", action: "updated",
data: { id: updatedFulfillment.id }, object: "fulfillment",
}), data: { id: updatedFulfillment.id },
buildExpectedEventMessageShape({ }),
eventName: FulfillmentEvents.FULFILLMENT_LABEL_DELETED, buildExpectedEventMessageShape({
action: "deleted", eventName: FulfillmentEvents.FULFILLMENT_LABEL_DELETED,
object: "fulfillment_label", action: "deleted",
data: { id: label3.id }, object: "fulfillment_label",
}), data: { id: label3.id },
buildExpectedEventMessageShape({ }),
eventName: FulfillmentEvents.FULFILLMENT_LABEL_UPDATED, buildExpectedEventMessageShape({
action: "updated", eventName: FulfillmentEvents.FULFILLMENT_LABEL_UPDATED,
object: "fulfillment_label", action: "updated",
data: { id: label2.id }, object: "fulfillment_label",
}), data: { id: label2.id },
buildExpectedEventMessageShape({ }),
eventName: FulfillmentEvents.FULFILLMENT_LABEL_CREATED, buildExpectedEventMessageShape({
action: "created", eventName: FulfillmentEvents.FULFILLMENT_LABEL_CREATED,
object: "fulfillment_label", action: "created",
data: { id: label4.id }, object: "fulfillment_label",
}), data: { id: label4.id },
]) }),
],
{
internal: true,
}
)
}) })
}) })
@@ -450,14 +465,20 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
expect(idempotentResult.canceled_at).toEqual(result.canceled_at) expect(idempotentResult.canceled_at).toEqual(result.canceled_at)
expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(1) expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(1)
expect(eventBusEmitSpy).toHaveBeenNthCalledWith(1, [ expect(eventBusEmitSpy).toHaveBeenNthCalledWith(
buildExpectedEventMessageShape({ 1,
eventName: FulfillmentEvents.FULFILLMENT_UPDATED, [
action: "updated", buildExpectedEventMessageShape({
object: "fulfillment", eventName: FulfillmentEvents.FULFILLMENT_UPDATED,
data: { id: fulfillment.id }, action: "updated",
}), object: "fulfillment",
]) data: { id: fulfillment.id },
}),
],
{
internal: true,
}
)
}) })
it("should fail to cancel a fulfillment that is already shipped", async () => { it("should fail to cancel a fulfillment that is already shipped", async () => {
@@ -107,14 +107,19 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
) )
expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(1) expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(1)
expect(eventBusEmitSpy).toHaveBeenCalledWith([ expect(eventBusEmitSpy).toHaveBeenCalledWith(
buildExpectedEventMessageShape({ [
eventName: FulfillmentEvents.GEO_ZONE_CREATED, buildExpectedEventMessageShape({
action: "created", eventName: FulfillmentEvents.GEO_ZONE_CREATED,
object: "geo_zone", action: "created",
data: { id: geoZone.id }, object: "geo_zone",
}), data: { id: geoZone.id },
]) }),
],
{
internal: true,
}
)
}) })
it("should create a collection of geo zones", async function () { it("should create a collection of geo zones", async function () {
@@ -165,7 +170,10 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
object: "geo_zone", object: "geo_zone",
data: { id: geoZones[i].id }, data: { id: geoZones[i].id },
}), }),
]) ]),
{
internal: true,
}
) )
++i ++i
@@ -265,14 +273,19 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
}) })
) )
expect(eventBusEmitSpy).toHaveBeenCalledWith([ expect(eventBusEmitSpy).toHaveBeenCalledWith(
buildExpectedEventMessageShape({ [
eventName: FulfillmentEvents.GEO_ZONE_UPDATED, buildExpectedEventMessageShape({
action: "updated", eventName: FulfillmentEvents.GEO_ZONE_UPDATED,
object: "geo_zone", action: "updated",
data: { id: updatedGeoZone.id }, object: "geo_zone",
}), data: { id: updatedGeoZone.id },
]) }),
],
{
internal: true,
}
)
}) })
it("should update a collection of geo zones", async function () { it("should update a collection of geo zones", async function () {
@@ -337,7 +350,10 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
object: "geo_zone", object: "geo_zone",
data: { id: expectedGeoZone.id }, data: { id: expectedGeoZone.id },
}), }),
]) ]),
{
internal: true,
}
) )
} }
}) })
@@ -366,32 +366,37 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
)! )!
expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(4) expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(4)
expect(eventBusEmitSpy).toHaveBeenCalledWith([ expect(eventBusEmitSpy).toHaveBeenCalledWith(
buildExpectedEventMessageShape({ [
eventName: FulfillmentEvents.GEO_ZONE_DELETED, buildExpectedEventMessageShape({
action: "deleted", eventName: FulfillmentEvents.GEO_ZONE_DELETED,
object: "geo_zone", action: "deleted",
data: { id: ukGeoZone.id }, object: "geo_zone",
}), data: { id: ukGeoZone.id },
buildExpectedEventMessageShape({ }),
eventName: FulfillmentEvents.SERVICE_ZONE_UPDATED, buildExpectedEventMessageShape({
action: "updated", eventName: FulfillmentEvents.SERVICE_ZONE_UPDATED,
object: "service_zone", action: "updated",
data: { id: updatedServiceZone.id }, object: "service_zone",
}), data: { id: updatedServiceZone.id },
buildExpectedEventMessageShape({ }),
eventName: FulfillmentEvents.GEO_ZONE_CREATED, buildExpectedEventMessageShape({
action: "created", eventName: FulfillmentEvents.GEO_ZONE_CREATED,
object: "geo_zone", action: "created",
data: { id: chGeoZone.id }, object: "geo_zone",
}), data: { id: chGeoZone.id },
buildExpectedEventMessageShape({ }),
eventName: FulfillmentEvents.GEO_ZONE_UPDATED, buildExpectedEventMessageShape({
action: "updated", eventName: FulfillmentEvents.GEO_ZONE_UPDATED,
object: "geo_zone", action: "updated",
data: { id: usGeoZone.id }, object: "geo_zone",
}), data: { id: usGeoZone.id },
]) }),
],
{
internal: true,
}
)
}) })
it("should fail on duplicated service zone name", async function () { it("should fail on duplicated service zone name", async function () {
@@ -517,26 +517,31 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
) )
expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(3) expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(3)
expect(eventBusEmitSpy).toHaveBeenCalledWith([ expect(eventBusEmitSpy).toHaveBeenCalledWith(
buildExpectedEventMessageShape({ [
eventName: FulfillmentEvents.SHIPPING_OPTION_CREATED, buildExpectedEventMessageShape({
action: "created", eventName: FulfillmentEvents.SHIPPING_OPTION_CREATED,
object: "shipping_option", action: "created",
data: { id: createdShippingOption.id }, object: "shipping_option",
}), data: { id: createdShippingOption.id },
buildExpectedEventMessageShape({ }),
eventName: FulfillmentEvents.SHIPPING_OPTION_TYPE_CREATED, buildExpectedEventMessageShape({
action: "created", eventName: FulfillmentEvents.SHIPPING_OPTION_TYPE_CREATED,
object: "shipping_option_type", action: "created",
data: { id: createdShippingOption.type.id }, object: "shipping_option_type",
}), data: { id: createdShippingOption.type.id },
buildExpectedEventMessageShape({ }),
eventName: FulfillmentEvents.SHIPPING_OPTION_RULE_CREATED, buildExpectedEventMessageShape({
action: "created", eventName: FulfillmentEvents.SHIPPING_OPTION_RULE_CREATED,
object: "shipping_option_rule", action: "created",
data: { id: createdShippingOption.rules[0].id }, object: "shipping_option_rule",
}), data: { id: createdShippingOption.rules[0].id },
]) }),
],
{
internal: true,
}
)
}) })
it("should create multiple new shipping options", async function () { it("should create multiple new shipping options", async function () {
@@ -624,7 +629,10 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
object: "shipping_option_rule", object: "shipping_option_rule",
data: { id: createdShippingOptions[i].rules[0].id }, data: { id: createdShippingOptions[i].rules[0].id },
}), }),
]) ]),
{
internal: true,
}
) )
++i ++i
@@ -819,7 +827,10 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
object: "shipping_option_rule", object: "shipping_option_rule",
data: { id: updatedShippingOption.rules[0].id }, data: { id: updatedShippingOption.rules[0].id },
}), }),
]) ]),
{
internal: true,
}
) )
}) })
@@ -1247,14 +1258,19 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
) )
expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(1) expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(1)
expect(eventBusEmitSpy).toHaveBeenCalledWith([ expect(eventBusEmitSpy).toHaveBeenCalledWith(
buildExpectedEventMessageShape({ [
eventName: FulfillmentEvents.SHIPPING_OPTION_RULE_CREATED, buildExpectedEventMessageShape({
action: "created", eventName: FulfillmentEvents.SHIPPING_OPTION_RULE_CREATED,
object: "shipping_option_rule", action: "created",
data: { id: rule.id }, object: "shipping_option_rule",
}), data: { id: rule.id },
]) }),
],
{
internal: true,
}
)
const rules = await service.listShippingOptionRules() const rules = await service.listShippingOptionRules()
expect(rules).toHaveLength(2) expect(rules).toHaveLength(2)
@@ -1324,14 +1340,19 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
}) })
) )
expect(eventBusEmitSpy).toHaveBeenCalledWith([ expect(eventBusEmitSpy).toHaveBeenCalledWith(
buildExpectedEventMessageShape({ [
eventName: FulfillmentEvents.SHIPPING_OPTION_RULE_UPDATED, buildExpectedEventMessageShape({
action: "updated", eventName: FulfillmentEvents.SHIPPING_OPTION_RULE_UPDATED,
object: "shipping_option_rule", action: "updated",
data: { id: updatedRule.id }, object: "shipping_option_rule",
}), data: { id: updatedRule.id },
]) }),
],
{
internal: true,
}
)
}) })
it("should fail to update a non-existent shipping option rule", async () => { it("should fail to update a non-existent shipping option rule", async () => {
@@ -45,14 +45,19 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
) )
expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(1) expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(1)
expect(eventBusEmitSpy).toHaveBeenCalledWith([ expect(eventBusEmitSpy).toHaveBeenCalledWith(
buildExpectedEventMessageShape({ [
eventName: FulfillmentEvents.SHIPPING_PROFILE_CREATED, buildExpectedEventMessageShape({
action: "created", eventName: FulfillmentEvents.SHIPPING_PROFILE_CREATED,
object: "shipping_profile", action: "created",
data: { id: createdShippingProfile.id }, object: "shipping_profile",
}), data: { id: createdShippingProfile.id },
]) }),
],
{
internal: true,
}
)
}) })
it("should create multiple new shipping profiles", async function () { it("should create multiple new shipping profiles", async function () {
@@ -90,7 +95,10 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
object: "shipping_profile", object: "shipping_profile",
data: { id: createdShippingProfiles[i].id }, data: { id: createdShippingProfiles[i].id },
}), }),
]) ]),
{
internal: true,
}
) )
++i ++i
@@ -14,18 +14,18 @@ import {
UpdateServiceZoneDTO, UpdateServiceZoneDTO,
} from "@medusajs/types" } from "@medusajs/types"
import { import {
EmitEvents,
InjectManager,
InjectTransactionManager,
MedusaContext,
MedusaError,
ModulesSdkUtils,
arrayDifference, arrayDifference,
deepEqualObj, deepEqualObj,
EmitEvents,
getSetDifference, getSetDifference,
InjectManager,
InjectTransactionManager,
isDefined, isDefined,
isPresent, isPresent,
isString, isString,
MedusaContext,
MedusaError,
ModulesSdkUtils,
promiseAll, promiseAll,
} from "@medusajs/utils" } from "@medusajs/utils"
import { import {
@@ -12,19 +12,19 @@ import {
} from "@medusajs/types" } from "@medusajs/types"
import { IInventoryService } from "@medusajs/types/dist/inventory" import { IInventoryService } from "@medusajs/types/dist/inventory"
import { import {
arrayDifference,
BigNumber, BigNumber,
CommonEvents, CommonEvents,
EmitEvents, EmitEvents,
InjectManager, InjectManager,
InjectTransactionManager, InjectTransactionManager,
InventoryEvents, InventoryEvents,
isDefined,
isString,
MathBN, MathBN,
MedusaContext, MedusaContext,
MedusaError, MedusaError,
MedusaService, MedusaService,
arrayDifference,
isDefined,
isString,
partitionArray, partitionArray,
} from "@medusajs/utils" } from "@medusajs/utils"
import { InventoryItem, InventoryLevel, ReservationItem } from "@models" import { InventoryItem, InventoryLevel, ReservationItem } from "@models"
@@ -1,10 +1,10 @@
import { INotificationModuleService } from "@medusajs/types" import { INotificationModuleService } from "@medusajs/types"
import { import {
CommonEvents, CommonEvents,
composeMessage,
Module, Module,
Modules, Modules,
NotificationEvents, NotificationEvents,
composeMessage,
} from "@medusajs/utils" } from "@medusajs/utils"
import { import {
MockEventBusService, MockEventBusService,
@@ -94,14 +94,19 @@ moduleIntegrationTestRunner({
const result = await service.createNotifications(notification) const result = await service.createNotifications(notification)
expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(1) expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(1)
expect(eventBusEmitSpy).toHaveBeenCalledWith([ expect(eventBusEmitSpy).toHaveBeenCalledWith(
composeMessage(NotificationEvents.NOTIFICATION_CREATED, { [
data: { id: result.id }, composeMessage(NotificationEvents.NOTIFICATION_CREATED, {
object: "notification", data: { id: result.id },
source: Modules.NOTIFICATION, object: "notification",
action: CommonEvents.CREATED, source: Modules.NOTIFICATION,
}), action: CommonEvents.CREATED,
]) }),
],
{
internal: true,
}
)
}) })
it("ensures the same notification is not sent twice", async () => { it("ensures the same notification is not sent twice", async () => {
@@ -1,10 +1,10 @@
import { IProductModuleService } from "@medusajs/types" import { IProductModuleService } from "@medusajs/types"
import { import {
CommonEvents, CommonEvents,
composeMessage,
Modules, Modules,
ProductEvents, ProductEvents,
ProductStatus, ProductStatus,
composeMessage,
} from "@medusajs/utils" } from "@medusajs/utils"
import { Product, ProductCategory } from "@models" import { Product, ProductCategory } from "@models"
import { import {
@@ -410,14 +410,19 @@ moduleIntegrationTestRunner<IProductModuleService>({
}) })
expect(eventBusSpy.mock.calls[0][0]).toHaveLength(1) expect(eventBusSpy.mock.calls[0][0]).toHaveLength(1)
expect(eventBusSpy).toHaveBeenCalledWith([ expect(eventBusSpy).toHaveBeenCalledWith(
composeMessage(ProductEvents.PRODUCT_CATEGORY_CREATED, { [
data: { id: category.id }, composeMessage(ProductEvents.PRODUCT_CATEGORY_CREATED, {
object: "product_category", data: { id: category.id },
source: Modules.PRODUCT, object: "product_category",
action: CommonEvents.CREATED, source: Modules.PRODUCT,
}), action: CommonEvents.CREATED,
]) }),
],
{
internal: true,
}
)
}) })
it("should append rank from an existing category depending on parent", async () => { it("should append rank from an existing category depending on parent", async () => {
@@ -505,14 +510,19 @@ moduleIntegrationTestRunner<IProductModuleService>({
}) })
expect(eventBusSpy.mock.calls[0][0]).toHaveLength(1) expect(eventBusSpy.mock.calls[0][0]).toHaveLength(1)
expect(eventBusSpy).toHaveBeenCalledWith([ expect(eventBusSpy).toHaveBeenCalledWith(
composeMessage(ProductEvents.PRODUCT_CATEGORY_UPDATED, { [
data: { id: productCategoryZero.id }, composeMessage(ProductEvents.PRODUCT_CATEGORY_UPDATED, {
object: "product_category", data: { id: productCategoryZero.id },
source: Modules.PRODUCT, object: "product_category",
action: CommonEvents.UPDATED, source: Modules.PRODUCT,
}), action: CommonEvents.UPDATED,
]) }),
],
{
internal: true,
}
)
}) })
it("should update the name of the category successfully", async () => { it("should update the name of the category successfully", async () => {
@@ -678,17 +688,22 @@ moduleIntegrationTestRunner<IProductModuleService>({
await service.deleteProductCategories([productCategoryOne.id]) await service.deleteProductCategories([productCategoryOne.id])
expect(eventBusSpy).toHaveBeenCalledTimes(1) expect(eventBusSpy).toHaveBeenCalledTimes(1)
expect(eventBusSpy).toHaveBeenCalledWith([ expect(eventBusSpy).toHaveBeenCalledWith(
expect.objectContaining({ [
data: { id: productCategoryOne.id }, expect.objectContaining({
name: "product-category.deleted", data: { id: productCategoryOne.id },
metadata: { name: "product-category.deleted",
action: "", metadata: {
object: "", action: "",
source: "", object: "",
}, source: "",
}), },
]) }),
],
{
internal: true,
}
)
}) })
it("should throw an error when an id does not exist", async () => { it("should throw an error when an id does not exist", async () => {
@@ -278,17 +278,22 @@ moduleIntegrationTestRunner<IProductModuleService>({
await service.deleteProductCollections([collectionId]) await service.deleteProductCollections([collectionId])
expect(eventBusSpy).toHaveBeenCalledTimes(1) expect(eventBusSpy).toHaveBeenCalledTimes(1)
expect(eventBusSpy).toHaveBeenCalledWith([ expect(eventBusSpy).toHaveBeenCalledWith(
{ [
name: "product-collection.deleted", {
data: { id: collectionId }, name: "product-collection.deleted",
metadata: { data: { id: collectionId },
action: "", metadata: {
object: "", action: "",
source: "", object: "",
source: "",
},
}, },
}, ],
]) {
internal: true,
}
)
}) })
}) })
@@ -306,12 +311,17 @@ moduleIntegrationTestRunner<IProductModuleService>({
]) ])
expect(eventBusSpy).toHaveBeenCalledTimes(1) expect(eventBusSpy).toHaveBeenCalledTimes(1)
expect(eventBusSpy).toHaveBeenCalledWith([ expect(eventBusSpy).toHaveBeenCalledWith(
[
{
data: { id: collectionId },
name: "product-collection.updated",
},
],
{ {
data: { id: collectionId }, internal: true,
name: "product-collection.updated", }
}, )
])
}) })
it("should update the value of the collection successfully", async () => { it("should update the value of the collection successfully", async () => {
@@ -502,12 +512,17 @@ moduleIntegrationTestRunner<IProductModuleService>({
]) ])
expect(eventBusSpy).toHaveBeenCalledTimes(1) expect(eventBusSpy).toHaveBeenCalledTimes(1)
expect(eventBusSpy).toHaveBeenCalledWith([ expect(eventBusSpy).toHaveBeenCalledWith(
[
{
data: { id: collections[0].id },
name: "product-collection.created",
},
],
{ {
data: { id: collections[0].id }, internal: true,
name: "product-collection.created", }
}, )
])
}) })
}) })
}) })
@@ -278,14 +278,19 @@ moduleIntegrationTestRunner<IProductModuleService>({
expect(productTag.value).toEqual("UK") expect(productTag.value).toEqual("UK")
expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(1) expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(1)
expect(eventBusEmitSpy).toHaveBeenCalledWith([ expect(eventBusEmitSpy).toHaveBeenCalledWith(
composeMessage(ProductEvents.PRODUCT_TAG_UPDATED, { [
data: { id: productTag.id }, composeMessage(ProductEvents.PRODUCT_TAG_UPDATED, {
object: "product_tag", data: { id: productTag.id },
source: Modules.PRODUCT, object: "product_tag",
action: CommonEvents.UPDATED, source: Modules.PRODUCT,
}), action: CommonEvents.UPDATED,
]) }),
],
{
internal: true,
}
)
}) })
it("should throw an error when an id does not exist", async () => { it("should throw an error when an id does not exist", async () => {
@@ -320,14 +325,19 @@ moduleIntegrationTestRunner<IProductModuleService>({
expect(productTag[0]?.value).toEqual("UK") expect(productTag[0]?.value).toEqual("UK")
expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(1) expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(1)
expect(eventBusEmitSpy).toHaveBeenCalledWith([ expect(eventBusEmitSpy).toHaveBeenCalledWith(
composeMessage(ProductEvents.PRODUCT_TAG_CREATED, { [
data: { id: productTag[0].id }, composeMessage(ProductEvents.PRODUCT_TAG_CREATED, {
object: "product_tag", data: { id: productTag[0].id },
source: Modules.PRODUCT, object: "product_tag",
action: CommonEvents.CREATED, source: Modules.PRODUCT,
}), action: CommonEvents.CREATED,
]) }),
],
{
internal: true,
}
)
}) })
}) })
@@ -374,20 +384,25 @@ moduleIntegrationTestRunner<IProductModuleService>({
const updatedTag = productTags.find((t) => t.value === "updated")! const updatedTag = productTags.find((t) => t.value === "updated")!
expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(2) expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(2)
expect(eventBusEmitSpy).toHaveBeenCalledWith([ expect(eventBusEmitSpy).toHaveBeenCalledWith(
composeMessage(ProductEvents.PRODUCT_TAG_CREATED, { [
data: { id: newTag.id }, composeMessage(ProductEvents.PRODUCT_TAG_CREATED, {
object: "product_tag", data: { id: newTag.id },
source: Modules.PRODUCT, object: "product_tag",
action: CommonEvents.CREATED, source: Modules.PRODUCT,
}), action: CommonEvents.CREATED,
composeMessage(ProductEvents.PRODUCT_TAG_UPDATED, { }),
data: { id: updatedTag.id }, composeMessage(ProductEvents.PRODUCT_TAG_UPDATED, {
object: "product_tag", data: { id: updatedTag.id },
source: Modules.PRODUCT, object: "product_tag",
action: CommonEvents.UPDATED, source: Modules.PRODUCT,
}), action: CommonEvents.UPDATED,
]) }),
],
{
internal: true,
}
)
}) })
}) })
}) })
@@ -212,14 +212,19 @@ moduleIntegrationTestRunner<IProductModuleService>({
expect(productVariant.title).toEqual("new test") expect(productVariant.title).toEqual("new test")
expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(1) expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(1)
expect(eventBusEmitSpy).toHaveBeenCalledWith([ expect(eventBusEmitSpy).toHaveBeenCalledWith(
composeMessage(ProductEvents.PRODUCT_VARIANT_UPDATED, { [
data: { id: variantOne.id }, composeMessage(ProductEvents.PRODUCT_VARIANT_UPDATED, {
object: "product_variant", data: { id: variantOne.id },
source: Modules.PRODUCT, object: "product_variant",
action: CommonEvents.UPDATED, source: Modules.PRODUCT,
}), action: CommonEvents.UPDATED,
]) }),
],
{
internal: true,
}
)
}) })
it("should upsert the options of a variant successfully", async () => { it("should upsert the options of a variant successfully", async () => {
@@ -245,14 +250,19 @@ moduleIntegrationTestRunner<IProductModuleService>({
) )
expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(1) expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(1)
expect(eventBusEmitSpy).toHaveBeenCalledWith([ expect(eventBusEmitSpy).toHaveBeenCalledWith(
composeMessage(ProductEvents.PRODUCT_VARIANT_UPDATED, { [
data: { id: variantOne.id }, composeMessage(ProductEvents.PRODUCT_VARIANT_UPDATED, {
object: "product_variant", data: { id: variantOne.id },
source: Modules.PRODUCT, object: "product_variant",
action: CommonEvents.UPDATED, source: Modules.PRODUCT,
}), action: CommonEvents.UPDATED,
]) }),
],
{
internal: true,
}
)
}) })
it("should do a partial update on the options of a variant successfully", async () => { it("should do a partial update on the options of a variant successfully", async () => {
@@ -319,14 +329,19 @@ moduleIntegrationTestRunner<IProductModuleService>({
) )
expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(1) expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(1)
expect(eventBusEmitSpy).toHaveBeenCalledWith([ expect(eventBusEmitSpy).toHaveBeenCalledWith(
composeMessage(ProductEvents.PRODUCT_VARIANT_CREATED, { [
data: { id: variant.id }, composeMessage(ProductEvents.PRODUCT_VARIANT_CREATED, {
object: "product_variant", data: { id: variant.id },
source: Modules.PRODUCT, object: "product_variant",
action: CommonEvents.CREATED, source: Modules.PRODUCT,
}), action: CommonEvents.CREATED,
]) }),
],
{
internal: true,
}
)
}) })
it("should correctly associate variants with own product options", async () => { it("should correctly associate variants with own product options", async () => {
@@ -374,12 +374,17 @@ moduleIntegrationTestRunner<IProductModuleService>({
await service.upsertProducts([updateData]) await service.upsertProducts([updateData])
expect(eventBusSpy).toHaveBeenCalledTimes(1) expect(eventBusSpy).toHaveBeenCalledTimes(1)
expect(eventBusSpy).toHaveBeenCalledWith([ expect(eventBusSpy).toHaveBeenCalledWith(
[
{
name: "product.updated",
data: { id: productOne.id },
},
],
{ {
name: "product.updated", internal: true,
data: { id: productOne.id }, }
}, )
])
}) })
it("should add relationships to a product", async () => { it("should add relationships to a product", async () => {
@@ -724,12 +729,17 @@ moduleIntegrationTestRunner<IProductModuleService>({
const products = await service.createProducts([data]) const products = await service.createProducts([data])
expect(eventBusSpy).toHaveBeenCalledTimes(1) expect(eventBusSpy).toHaveBeenCalledTimes(1)
expect(eventBusSpy).toHaveBeenCalledWith([ expect(eventBusSpy).toHaveBeenCalledWith(
[
{
name: "product.created",
data: { id: products[0].id },
},
],
{ {
name: "product.created", internal: true,
data: { id: products[0].id }, }
}, )
])
}) })
}) })
@@ -814,12 +824,17 @@ moduleIntegrationTestRunner<IProductModuleService>({
await service.softDeleteProducts([products[0].id]) await service.softDeleteProducts([products[0].id])
expect(eventBusSpy).toHaveBeenCalledWith([ expect(eventBusSpy).toHaveBeenCalledWith(
[
{
name: "product.created",
data: { id: products[0].id },
},
],
{ {
name: "product.created", internal: true,
data: { id: products[0].id }, }
}, )
])
}) })
}) })
@@ -8,10 +8,10 @@ import {
ProductTypes, ProductTypes,
} from "@medusajs/types" } from "@medusajs/types"
import { import {
Image as ProductImage,
Product, Product,
ProductCategory, ProductCategory,
ProductCollection, ProductCollection,
Image as ProductImage,
ProductOption, ProductOption,
ProductOptionValue, ProductOptionValue,
ProductTag, ProductTag,
@@ -875,7 +875,10 @@ export default class ProductModuleService
collections.map(({ id }) => ({ collections.map(({ id }) => ({
name: ProductCollectionEvents.COLLECTION_CREATED, name: ProductCollectionEvents.COLLECTION_CREATED,
data: { id }, data: { id },
})) })),
{
internal: true,
}
) )
return Array.isArray(data) ? createdCollections : createdCollections[0] return Array.isArray(data) ? createdCollections : createdCollections[0]
@@ -948,7 +951,10 @@ export default class ProductModuleService
created.map(({ id }) => ({ created.map(({ id }) => ({
name: ProductCollectionEvents.COLLECTION_CREATED, name: ProductCollectionEvents.COLLECTION_CREATED,
data: { id }, data: { id },
})) })),
{
internal: true,
}
) )
} }
@@ -957,7 +963,10 @@ export default class ProductModuleService
updated.map(({ id }) => ({ updated.map(({ id }) => ({
name: ProductCollectionEvents.COLLECTION_UPDATED, name: ProductCollectionEvents.COLLECTION_UPDATED,
data: { id }, data: { id },
})) })),
{
internal: true,
}
) )
} }
@@ -1018,7 +1027,10 @@ export default class ProductModuleService
updatedCollections.map(({ id }) => ({ updatedCollections.map(({ id }) => ({
name: ProductCollectionEvents.COLLECTION_UPDATED, name: ProductCollectionEvents.COLLECTION_UPDATED,
data: { id }, data: { id },
})) })),
{
internal: true,
}
) )
return isString(idOrSelector) ? updatedCollections[0] : updatedCollections return isString(idOrSelector) ? updatedCollections[0] : updatedCollections
@@ -1281,7 +1293,10 @@ export default class ProductModuleService
createdProducts.map(({ id }) => ({ createdProducts.map(({ id }) => ({
name: ProductEvents.PRODUCT_CREATED, name: ProductEvents.PRODUCT_CREATED,
data: { id }, data: { id },
})) })),
{
internal: true,
}
) )
return Array.isArray(data) ? createdProducts : createdProducts[0] return Array.isArray(data) ? createdProducts : createdProducts[0]
@@ -1329,7 +1344,10 @@ export default class ProductModuleService
created.map(({ id }) => ({ created.map(({ id }) => ({
name: ProductEvents.PRODUCT_CREATED, name: ProductEvents.PRODUCT_CREATED,
data: { id }, data: { id },
})) })),
{
internal: true,
}
) )
} }
@@ -1338,7 +1356,10 @@ export default class ProductModuleService
updated.map(({ id }) => ({ updated.map(({ id }) => ({
name: ProductEvents.PRODUCT_UPDATED, name: ProductEvents.PRODUCT_UPDATED,
data: { id }, data: { id },
})) })),
{
internal: true,
}
) )
} }
@@ -1392,7 +1413,10 @@ export default class ProductModuleService
updatedProducts.map(({ id }) => ({ updatedProducts.map(({ id }) => ({
name: ProductEvents.PRODUCT_UPDATED, name: ProductEvents.PRODUCT_UPDATED,
data: { id }, data: { id },
})) })),
{
internal: true,
}
) )
return isString(idOrSelector) ? updatedProducts[0] : updatedProducts return isString(idOrSelector) ? updatedProducts[0] : updatedProducts
@@ -172,12 +172,17 @@ moduleIntegrationTestRunner<IUserModuleService>({
]) ])
expect(eventBusSpy).toHaveBeenCalledTimes(1) expect(eventBusSpy).toHaveBeenCalledTimes(1)
expect(eventBusSpy).toHaveBeenCalledWith([ expect(eventBusSpy).toHaveBeenCalledWith(
expect.objectContaining({ [
data: { id: "1" }, expect.objectContaining({
name: UserEvents.INVITE_UPDATED, data: { id: "1" },
}), name: UserEvents.INVITE_UPDATED,
]) }),
],
{
internal: true,
}
)
}) })
}) })
@@ -189,12 +194,17 @@ moduleIntegrationTestRunner<IUserModuleService>({
await service.refreshInviteTokens(["1"]) await service.refreshInviteTokens(["1"])
expect(eventBusSpy).toHaveBeenCalledTimes(2) expect(eventBusSpy).toHaveBeenCalledTimes(2)
expect(eventBusSpy).toHaveBeenCalledWith([ expect(eventBusSpy).toHaveBeenCalledWith(
expect.objectContaining({ [
data: { id: "1" }, expect.objectContaining({
name: UserEvents.INVITE_TOKEN_GENERATED, data: { id: "1" },
}), name: UserEvents.INVITE_TOKEN_GENERATED,
]) }),
],
{
internal: true,
}
)
}) })
}) })
describe("createInvitie", () => { describe("createInvitie", () => {
@@ -218,24 +228,29 @@ moduleIntegrationTestRunner<IUserModuleService>({
await service.createInvites(defaultInviteData) await service.createInvites(defaultInviteData)
expect(eventBusSpy).toHaveBeenCalledTimes(1) expect(eventBusSpy).toHaveBeenCalledTimes(1)
expect(eventBusSpy).toHaveBeenCalledWith([ expect(eventBusSpy).toHaveBeenCalledWith(
expect.objectContaining({ [
data: { id: "1" }, expect.objectContaining({
name: UserEvents.INVITE_CREATED, data: { id: "1" },
}), name: UserEvents.INVITE_CREATED,
expect.objectContaining({ }),
data: { id: "2" }, expect.objectContaining({
name: UserEvents.INVITE_CREATED, data: { id: "2" },
}), name: UserEvents.INVITE_CREATED,
expect.objectContaining({ }),
data: { id: "1" }, expect.objectContaining({
name: UserEvents.INVITE_TOKEN_GENERATED, data: { id: "1" },
}), name: UserEvents.INVITE_TOKEN_GENERATED,
expect.objectContaining({ }),
data: { id: "2" }, expect.objectContaining({
name: UserEvents.INVITE_TOKEN_GENERATED, data: { id: "2" },
}), name: UserEvents.INVITE_TOKEN_GENERATED,
]) }),
],
{
internal: true,
}
)
}) })
}) })
}) })
@@ -217,12 +217,17 @@ moduleIntegrationTestRunner<IUserModuleService>({
]) ])
expect(eventBusSpy).toHaveBeenCalledTimes(1) expect(eventBusSpy).toHaveBeenCalledTimes(1)
expect(eventBusSpy).toHaveBeenCalledWith([ expect(eventBusSpy).toHaveBeenCalledWith(
expect.objectContaining({ [
data: { id: "1" }, expect.objectContaining({
name: UserEvents.USER_UPDATED, data: { id: "1" },
}), name: UserEvents.USER_UPDATED,
]) }),
],
{
internal: true,
}
)
}) })
}) })
@@ -247,16 +252,21 @@ moduleIntegrationTestRunner<IUserModuleService>({
await service.createUsers(defaultUserData) await service.createUsers(defaultUserData)
expect(eventBusSpy).toHaveBeenCalledTimes(1) expect(eventBusSpy).toHaveBeenCalledTimes(1)
expect(eventBusSpy).toHaveBeenCalledWith([ expect(eventBusSpy).toHaveBeenCalledWith(
expect.objectContaining({ [
data: { id: "1" }, expect.objectContaining({
name: UserEvents.USER_CREATED, data: { id: "1" },
}), name: UserEvents.USER_CREATED,
expect.objectContaining({ }),
data: { id: "2" }, expect.objectContaining({
name: UserEvents.USER_CREATED, data: { id: "2" },
}), name: UserEvents.USER_CREATED,
]) }),
],
{
internal: true,
}
)
}) })
}) })
}) })