diff --git a/source/event.ts b/source/event.ts index 88fcd98b..4f862831 100644 --- a/source/event.ts +++ b/source/event.ts @@ -24,7 +24,7 @@ export class Event { constructor( topic: string, data: object, - options: { [key: string]: object } = {} + options: { [key: string]: unknown } = {} ) { this._data = { topic, @@ -41,7 +41,15 @@ export class Event { return this._data; } - /** Add source to event data. */ + /** Add source to event data, keeping any already avalable source information */ + prepareSource(source: object): void { + this._data.source = { + ...source, + ...this._data.source, + }; + } + + /** Add source to event data, replacing any previous data. */ addSource(source: any): void { this._data.source = source; } diff --git a/source/event_hub.ts b/source/event_hub.ts index 9b06bbb9..4b2c3174 100644 --- a/source/event_hub.ts +++ b/source/event_hub.ts @@ -271,7 +271,7 @@ export class EventHub { ); } - event.addSource({ + event.prepareSource({ id: this._id, applicationId: this._applicationId, user: { @@ -613,13 +613,11 @@ export class EventHub { data: Data, source: Data | null = null ): Promise { - const replyEvent = new Event("ftrack.meta.reply", { - ...data, + const replyEvent = new Event("ftrack.meta.reply", data, { target: `id=${sourceEventPayload.source.id}`, inReplyToEvent: sourceEventPayload.id, - source: source ?? data.source, + source: source, }); - return this.publish(replyEvent); } } diff --git a/test/event.test.ts b/test/event.test.ts new file mode 100644 index 00000000..2f3435a0 --- /dev/null +++ b/test/event.test.ts @@ -0,0 +1,98 @@ +// :copyright: Copyright (c) 2023 ftrack + +import { Event } from "../source/event"; +import { describe, expect, it } from "vitest"; + +describe("Event class", () => { + it("should initialize with correct topic and data", () => { + const event = new Event("testTopic", { key: "value" }); + const data = event.getData(); + expect(data.topic).toBe("testTopic"); + expect(data.data).toEqual({ key: "value" }); + }); + + it("should have default properties", () => { + const event = new Event("testTopic", { key: "value" }); + const data = event.getData(); + expect(data.target).toBe(""); + expect(data.inReplyToEvent).toBeNull(); + }); + + it("should set properties from options", () => { + const event = new Event( + "testTopic", + { key: "value" }, + { target: "sampleTarget", customOption: "customValue" } + ); + const data = event.getData(); + expect(data.target).toBe("sampleTarget"); + expect(data.customOption).toBe("customValue"); + }); + + it("should generate unique UUID", () => { + const event1 = new Event("testTopic", { key: "value" }); + const event2 = new Event("testTopic", { key: "value" }); + const data1 = event1.getData(); + const data2 = event2.getData(); + const uuidRegexExp = + /^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/gi; + expect(data1.id).not.toBe(data2.id); + expect(uuidRegexExp.test(data1.id)).toBe(true); + }); + + it("should add source to event data", () => { + const event = new Event("testTopic", { key: "value" }); + const source = { + id: "testId", + applicationId: "testApplicationId", + user: { + username: "testUser", + }, + }; + event.addSource(source); + const data = event.getData(); + expect(data.source).toBe(source); + }); + describe("prepareSource Method", () => { + it("should prepare and add source to event data", () => { + const event = new Event("testTopic", { key: "value" }); + event.prepareSource({ newKey: "newValue" }); + const data = event.getData(); + expect(data.source).toEqual({ newKey: "newValue" }); + }); + + it("should not override existing source when preparing a new source", () => { + const event = new Event( + "testTopic", + { key: "value" }, + { source: { oldKey: "oldValue" } } + ); + event.prepareSource({ oldKey: "newValue", newKey: "newValue" }); + const data = event.getData(); + expect(data.source).toEqual({ + oldKey: "oldValue", + newKey: "newValue", + }); + }); + it("should handle source undefined", () => { + const event = new Event( + "testTopic", + { key: "value" }, + { source: undefined } + ); + event.prepareSource({ newKey: "newValue" }); + const data = event.getData(); + expect(data.source).toEqual({ + newKey: "newValue", + }); + }); + it("Prepare should handle source null", () => { + const event = new Event("testTopic", { key: "value" }, { source: null }); + event.prepareSource({ newKey: "newValue" }); + const data = event.getData(); + expect(data.source).toEqual({ + newKey: "newValue", + }); + }); + }); +}); diff --git a/test/event_hub.test.ts b/test/event_hub.test.ts index 94d94cf6..d27585a9 100644 --- a/test/event_hub.test.ts +++ b/test/event_hub.test.ts @@ -1,4 +1,5 @@ import { EventHub } from "../source/event_hub"; +import { Event } from "../source/event"; import { vi, describe, expect, beforeEach, afterEach, test } from "vitest"; describe("EventHub", () => { @@ -208,4 +209,33 @@ describe("EventHub", () => { ); publishReplySpy.mockRestore(); }); + test("publishReply published Event with correct shape", async () => { + eventHub.publish = vi.fn(); + + const sourceEventPayload = { + source: { id: "testId" }, + id: "anotherTestId", + }; + + const data = { + someData: "value", + }; + + await eventHub.publishReply(sourceEventPayload, data); + + const publishedEvent = eventHub.publish.mock.calls[0][0]; + expect(publishedEvent).toBeInstanceOf(Event); + const EventData = publishedEvent.getData(); + // Ignoring the id field for comparison + delete EventData.id; + + const expectedEvent = { + topic: "ftrack.meta.reply", + data: { someData: "value" }, + source: null, + target: "id=testId", + inReplyToEvent: "anotherTestId", + }; + expect(EventData).toEqual(expectedEvent); + }); });