Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(shell/js): Fixed fdc3 DesktopAgent integration #250

Merged
merged 1 commit into from
Jul 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions src/shell/js/composeui-fdc3/src/ComposeUIDesktopAgent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,14 +102,15 @@ export class ComposeUIDesktopAgent implements DesktopAgent {
reject(new Error("The current channel have not been set."));
return;
}
if (typeof contextType != 'string' || !contextType) {
reject(new Error("The contextType was type of ContextHandler, which would use a deprecated function, please use string or null for contextType!"));
return;

if (contextType !=null && typeof contextType != 'string') {
handler = contextType;
contextType = null;
}

const listener = <ComposeUIListener>await this.currentChannel!.addContextListener(contextType, handler!);
const resultContext = await this.currentChannel!.getCurrentContext(contextType)
listener.latestContext = this.currentChannel!.retrieveCurrentContext(contextType);
const listener = <ComposeUIListener>await this.currentChannel!.addContextListener(contextType ?? null, handler!);
const resultContext = await this.currentChannel!.getCurrentContext(contextType ?? undefined)
listener.latestContext = this.currentChannel!.retrieveCurrentContext(contextType ?? undefined);
if (resultContext != listener.latestContext) {
//TODO: integrationtest
await listener.handleContextMessage();
Expand Down
85 changes: 38 additions & 47 deletions src/shell/js/composeui-fdc3/src/Fdc3ComposeUI.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import { ComposeUIListener } from './infrastructure/ComposeUIListener';
import { ComposeUIDesktopAgent } from './ComposeUIDesktopAgent';
import { ComposeUITopic } from './infrastructure/ComposeUITopic';
import { Channel, ChannelError, Context } from '@finos/fdc3';
import { Fdc3ContextMessage } from './infrastructure/messages/Fdc3ContextMessage';
import { Fdc3GetCurrentContextRequest } from './infrastructure/messages/Fdc3GetCurrentContextRequest';
import { Fdc3FindChannelRequest } from './infrastructure/messages/Fdc3FindChannelRequest';

Expand All @@ -32,7 +31,6 @@ const testInstrument = {
ticker: 'AAPL'
}
};
const dummyTopic= "dummyTopic";
const contextMessageHandlerMock = jest.fn((something) => {
return "dummy";
});
Expand All @@ -51,30 +49,28 @@ describe('Tests for ComposeUIChannel implementation API', () => {
unregisterEndpoint: jest.fn(() => { return Promise.resolve() }),
registerService: jest.fn(() => { return Promise.resolve() }),
unregisterService: jest.fn(() => { return Promise.resolve() }),
invoke: jest.fn(() => { return Promise.resolve(JSON.stringify({context: "", payload: `${JSON.stringify(new Fdc3ContextMessage(dummyChannelId, dummyContext))}` })) })
invoke: jest.fn(() => { return Promise.resolve(JSON.stringify(dummyContext))})
}
});

it('broadcast will call messageRouters publish method', async() => {
const testChannel = new ComposeUIChannel(dummyTopic, "user", messageRouterClient);
const testChannel = new ComposeUIChannel(dummyChannelId, "user", messageRouterClient);
await testChannel.broadcast(testInstrument);
expect(messageRouterClient.publish).toHaveBeenCalledTimes(1);
expect(messageRouterClient.publish).toHaveBeenCalledWith(ComposeUITopic.broadcast(), JSON.stringify(new Fdc3ContextMessage("dummyTopic", testInstrument)));
expect(messageRouterClient.publish).toHaveBeenCalledWith(ComposeUITopic.broadcast(dummyChannelId,"user"), JSON.stringify(testInstrument));
});

it('broadcast will set the lastContext to test instrument', async() => {
const testChannel = new ComposeUIChannel(dummyTopic, "user", messageRouterClient);
const testChannel = new ComposeUIChannel(dummyChannelId, "user", messageRouterClient);
await testChannel.broadcast(testInstrument);
const resultContext = await testChannel.getCurrentContext();
expect(messageRouterClient.publish).toHaveBeenCalledTimes(1);
expect(messageRouterClient.invoke).toHaveBeenCalledTimes(1);
expect(messageRouterClient.invoke).toHaveBeenCalledWith(ComposeUITopic.getCurrentContext(dummyTopic, testChannel.type), JSON.stringify(new Fdc3GetCurrentContextRequest(undefined)));
expect(messageRouterClient.publish).toHaveBeenCalledWith(ComposeUITopic.broadcast(), JSON.stringify(new Fdc3ContextMessage(dummyTopic, testInstrument)));
expect(resultContext).toMatchObject({id : dummyChannelId, context: dummyContext});
const resultContext = await testChannel.retrieveCurrentContext();
expect(messageRouterClient.publish).toHaveBeenCalledTimes(1);
expect(messageRouterClient.publish).toHaveBeenCalledWith(ComposeUITopic.broadcast(dummyChannelId, "user"), JSON.stringify(testInstrument));
expect(resultContext).toMatchObject(testInstrument);
});

it('getCurrentContext will result the lastContext', async() => {
const testChannel = new ComposeUIChannel(dummyTopic, "user", messageRouterClient);
const testChannel = new ComposeUIChannel(dummyChannelId, "user", messageRouterClient);
await testChannel.broadcast(testInstrument);
const testInstrument2 = {
type: 'fdc3.instrument',
Expand All @@ -83,37 +79,34 @@ describe('Tests for ComposeUIChannel implementation API', () => {
}
};
await testChannel.broadcast(testInstrument2);
const resultContext = await testChannel.getCurrentContext();
const resultContextWithContextType = await testChannel.getCurrentContext(testInstrument2.type);
expect(messageRouterClient.invoke).toBeCalledTimes(2);
const resultContext = await testChannel.retrieveCurrentContext();
const resultContextWithContextType = await testChannel.retrieveCurrentContext(testInstrument2.type);
expect(messageRouterClient.publish).toBeCalledTimes(2);
expect(messageRouterClient.publish).toHaveBeenCalledWith(ComposeUITopic.broadcast(), JSON.stringify(new Fdc3ContextMessage(dummyTopic, testInstrument)));
expect(messageRouterClient.publish).toHaveBeenCalledWith(ComposeUITopic.broadcast(), JSON.stringify(new Fdc3ContextMessage(dummyTopic, testInstrument2)));
expect(messageRouterClient.invoke).toHaveBeenCalledWith(ComposeUITopic.getCurrentContext(dummyTopic, testChannel.type), JSON.stringify(new Fdc3GetCurrentContextRequest(undefined)));
expect(messageRouterClient.invoke).toHaveBeenCalledWith(ComposeUITopic.getCurrentContext(dummyTopic, testChannel.type), JSON.stringify(new Fdc3GetCurrentContextRequest(testInstrument2.type)));
expect(resultContext).toMatchObject({id : dummyChannelId, context: dummyContext});
expect(messageRouterClient.publish).toHaveBeenCalledWith(ComposeUITopic.broadcast(dummyChannelId, "user"), JSON.stringify(testInstrument));
expect(messageRouterClient.publish).toHaveBeenCalledWith(ComposeUITopic.broadcast(dummyChannelId, "user"), JSON.stringify(testInstrument2));
expect(resultContext).toMatchObject(testInstrument2);
expect(resultContextWithContextType).toMatchObject<Partial<Context>>(testInstrument2);
});

it('getCurrentContext will return null as per the given contextType couldnt be found in the saved contexts', async() =>{
const testChannel = new ComposeUIChannel(dummyTopic, "user", messageRouterClient);
const result = await testChannel.getCurrentContext("dummyContextType");
const testChannel = new ComposeUIChannel(dummyChannelId, "user", messageRouterClient);
const result = await testChannel.retrieveCurrentContext("dummyContextType");
expect(result).toBe(null);
});

it('addContextListener will result a ComposeUIListener', async() => {
const testChannel = new ComposeUIChannel(dummyTopic, "user", messageRouterClient);
const testChannel = new ComposeUIChannel(dummyChannelId, "user", messageRouterClient);
await testChannel.broadcast(testInstrument);
const resultListener = await testChannel.addContextListener('fdc3.instrument', contextMessageHandlerMock);
expect(resultListener).toBeInstanceOf(ComposeUIListener);
expect(contextMessageHandlerMock).toHaveBeenCalledTimes(0); //as per the standard
});

it('addContextListener will fail as per contexType is ContextHandler', async() => {
const testChannel = new ComposeUIChannel(dummyTopic, "user", messageRouterClient);
await expect(testChannel.addContextListener(test => {}))
.rejects
.toThrow("addContextListener with contextType as ContextHandler is deprecated, please use the newer version.");
it('addContextListener will treat contexType is ContextHandler as all types', async() => {
const testChannel = new ComposeUIChannel(dummyChannelId, "user", messageRouterClient);
const resultListener = await testChannel.addContextListener(test => {});
expect(resultListener).toBeInstanceOf(ComposeUIListener);
expect(messageRouterClient.subscribe).toBeCalledTimes(1);
});
});

Expand All @@ -130,55 +123,54 @@ describe('Tests for ComposeUIListener implementation API', () => {
unregisterEndpoint: jest.fn(() => { return Promise.resolve() }),
registerService: jest.fn(() => { return Promise.resolve() }),
unregisterService: jest.fn(() => { return Promise.resolve() }),
invoke: jest.fn(() => { return Promise.resolve(JSON.stringify({context: "", payload: `${JSON.stringify(new Fdc3ContextMessage(dummyChannelId, dummyContext))}` })) })
invoke: jest.fn(() => { return Promise.resolve(JSON.stringify({context: "", payload: `${JSON.stringify(dummyContext)}` })) })
}
});

it('subscribe will call messagerouter subscribe method', async() => {
const testListener = new ComposeUIListener(messageRouterClient, instrument => { console.log(instrument); }, "dummyChannelId", "fdc3.instrument");
const testListener = new ComposeUIListener(messageRouterClient, instrument => { console.log(instrument); }, "dummyChannelId", "user", "fdc3.instrument");
await testListener.subscribe();
expect(messageRouterClient.subscribe).toHaveBeenCalledTimes(1);
//expect(messageRouterClient.subscribe).toHaveBeenCalledWith(ComposeUITopic.broadcast("dummyChannelId"), jest.fn());
});

it('handleContextMessage will trigger the handler', async() => {
const testListener = new ComposeUIListener(messageRouterClient, contextMessageHandlerMock, undefined, "fdc3.instrument");
const testListener = new ComposeUIListener(messageRouterClient, contextMessageHandlerMock, "", "user", "fdc3.instrument");
await testListener.subscribe();
await testListener.handleContextMessage(testInstrument);
expect(contextMessageHandlerMock).toHaveBeenCalledWith(testInstrument);
});

it('handleContextMessage will resolve the LatestContext saved for ComposeUIListener', async() => {
const testListener = new ComposeUIListener(messageRouterClient, contextMessageHandlerMock, undefined, "fdc3.instrument");
const testListener = new ComposeUIListener(messageRouterClient, contextMessageHandlerMock, "", "user", "fdc3.instrument");
await testListener.subscribe();
testListener.latestContext = testInstrument;
await testListener.handleContextMessage();
expect(contextMessageHandlerMock).toHaveBeenCalledWith(testListener.latestContext);
});

it('handleContextMessage will resolve an empty context', async() => {
const testListener = new ComposeUIListener(messageRouterClient, contextMessageHandlerMock, undefined, "fdc3.instrument");
const testListener = new ComposeUIListener(messageRouterClient, contextMessageHandlerMock, "", "user", "fdc3.instrument");
await testListener.subscribe();
await testListener.handleContextMessage();
expect(contextMessageHandlerMock).toHaveBeenCalledWith({type: ""});
});

it('handleContextMessage will be rejected with Error as no handler', async() => {
const testListener = new ComposeUIListener(messageRouterClient, contextMessageHandlerMock, undefined, "fdc3.instrument");
const testListener = new ComposeUIListener(messageRouterClient, contextMessageHandlerMock, "", "user", "fdc3.instrument");
await expect(testListener.handleContextMessage(testInstrument))
.rejects
.toThrow("The current listener is not subscribed.");
});

it('unsubscribe will be true', async() => {
const testListener = new ComposeUIListener(messageRouterClient, contextMessageHandlerMock, "dummyChannelId", "fdc3.instrument");
const testListener = new ComposeUIListener(messageRouterClient, contextMessageHandlerMock, "dummyChannelId", "user", "fdc3.instrument");
await testListener.subscribe();
const resultUnsubscription = testListener.unsubscribe();
expect(resultUnsubscription).toBeTruthy();
});

it('unsubscribe will be false', async() => {
const testListener = new ComposeUIListener(messageRouterClient, contextMessageHandlerMock, undefined, "fdc3.instrument");
const testListener = new ComposeUIListener(messageRouterClient, contextMessageHandlerMock, "", "user", "fdc3.instrument");
const resultUnsubscription = testListener.unsubscribe();
expect(resultUnsubscription).toBeFalsy();
});
Expand All @@ -198,16 +190,16 @@ describe('Tests for ComposeUIDesktopAgent implementation API', () => {
unregisterEndpoint: jest.fn(() => { return Promise.resolve() }),
registerService: jest.fn(() => { return Promise.resolve() }),
unregisterService: jest.fn(() => { return Promise.resolve() }),
invoke: jest.fn(() => { return Promise.resolve(JSON.stringify({context: "", payload: `${JSON.stringify(new Fdc3ContextMessage(dummyChannelId, dummyContext))}` })) })
invoke: jest.fn(() => { return Promise.resolve(JSON.stringify({context: "", payload: `${JSON.stringify(dummyContext)}` })) })
}
});

it('broadcast will trigger publish method of the messageRouter', async() => {
const testDesktopAgent = new ComposeUIDesktopAgent(dummyTopic, messageRouterClient);
await testDesktopAgent.joinUserChannel(dummyTopic);
const testDesktopAgent = new ComposeUIDesktopAgent(dummyChannelId, messageRouterClient);
await testDesktopAgent.joinUserChannel(dummyChannelId);
await testDesktopAgent.broadcast(testInstrument);
expect(messageRouterClient.publish).toBeCalledTimes(1);
expect(messageRouterClient.publish).toHaveBeenCalledWith(ComposeUITopic.broadcast(), JSON.stringify(new Fdc3ContextMessage(dummyTopic, testInstrument)));
expect(messageRouterClient.publish).toHaveBeenCalledWith(ComposeUITopic.broadcast(dummyChannelId, "user"), JSON.stringify(testInstrument));
});

it('broadcast will fail as per the current channel is not defined', async() => {
Expand All @@ -234,13 +226,12 @@ describe('Tests for ComposeUIDesktopAgent implementation API', () => {
expect(messageRouterClient.subscribe).toBeCalledTimes(0);
});

it('addContextListener will fail as per the type of the context type is a function', async() => {
it('addContextListener will treat function context type as all types', async() => {
const testDesktopAgent = new ComposeUIDesktopAgent("dummyPath", messageRouterClient);
await testDesktopAgent.joinUserChannel("dummyPath");
await expect(testDesktopAgent.addContextListener(contextMessageHandlerMock))
.rejects
.toThrow("The contextType was type of ContextHandler, which would use a deprecated function, please use string or null for contextType!");
expect(messageRouterClient.subscribe).toBeCalledTimes(0);
var resultListener = await testDesktopAgent.addContextListener(contextMessageHandlerMock)
expect(resultListener).toBeInstanceOf(ComposeUIListener);
expect(messageRouterClient.subscribe).toBeCalledTimes(1);
});

it('getUserChannels will return the created userchannels', async() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import { Channel, Context, ContextHandler, DisplayMetadata, Listener } from "@fi
import { MessageRouter, TopicMessage } from "@morgan-stanley/composeui-messaging-client";
import { ChannelType } from "./ChannelType";
import { ComposeUIListener } from "./ComposeUIListener";
import { Fdc3ContextMessage } from "./messages/Fdc3ContextMessage";
import { Fdc3GetCurrentContextRequest } from "./messages/Fdc3GetCurrentContextRequest";
import { ComposeUITopic } from "./ComposeUITopic";

Expand All @@ -39,9 +38,8 @@ export class ComposeUIChannel implements Channel {
//Setting the last published context message.
this.lastContexts.set(context.type, context);
this.lastContext = context;
const message = new Fdc3ContextMessage(this.id, context);
const topic = ComposeUITopic.broadcast();
await this.messageRouterClient.publish(topic, JSON.stringify(message));
const topic = ComposeUITopic.broadcast(this.id, this.type);
await this.messageRouterClient.publish(topic, JSON.stringify(context));
}

//TODO add error
Expand All @@ -50,13 +48,10 @@ export class ComposeUIChannel implements Channel {
const message = JSON.stringify(new Fdc3GetCurrentContextRequest(contextType));
const response = await this.messageRouterClient.invoke(ComposeUITopic.getCurrentContext(this.id, this.type), message);
if (response) {
const topicMessage = <TopicMessage>JSON.parse(response);
if(topicMessage.payload) {
const context = <Context>JSON.parse(topicMessage.payload);
if(context) {
this.lastContext = context;
this.lastContexts.set(context.type, context);
}
const context = <Context>JSON.parse(response);
if(context) {
this.lastContext = context;
this.lastContexts.set(context.type, context);
}
}
resolve(this.retrieveCurrentContext(contextType));
Expand All @@ -80,12 +75,13 @@ export class ComposeUIChannel implements Channel {
public addContextListener(contextType: string | null, handler: ContextHandler): Promise<Listener>;
public addContextListener(handler: ContextHandler): Promise<Listener>;
public async addContextListener(contextType: any, handler?: any): Promise<Listener> {
if (typeof contextType != 'string' && contextType != null) {
throw new Error("addContextListener with contextType as ContextHandler is deprecated, please use the newer version.");
} else {
const listener = new ComposeUIListener(this.messageRouterClient, handler, this.id, contextType);
await listener.subscribe();
return listener;
};
if (contextType != null && typeof contextType != 'string') {
handler = contextType;
contextType = null;
}

const listener = new ComposeUIListener(this.messageRouterClient, handler, this.id, this.type, contextType);
await listener.subscribe();
return listener;
}
}
Loading