Skip to content
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

## [Unreleased]
* Enhanced method binding for FDC3 API objects to support destructuring. All public methods of `Channel`, `PrivateChannel`, and `IntentResolution` objects are now properly bound to their instances using `.bind(this)` in their constructors. ([#1645](https://github.com/finos/FDC3/issues/1645))

### Added
* Add a notes field to Trade type ([#1563](https://github.com/finos/FDC3/pull/1563))
Expand Down
5 changes: 5 additions & 0 deletions packages/fdc3-agent-proxy/src/channels/DefaultChannel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ export class DefaultChannel implements Channel {
this.id = id;
this.type = type;
this.displayMetadata = displayMetadata;

//bind all functions to allow destructuring
this.broadcast = this.broadcast.bind(this);
this.getCurrentContext = this.getCurrentContext.bind(this);
this.addContextListener = this.addContextListener.bind(this);
}

async broadcast(context: Context): Promise<void> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ import {
export class DefaultPrivateChannel extends DefaultChannel implements PrivateChannel {
constructor(messaging: Messaging, messageExchangeTimeout: number, id: string) {
super(messaging, messageExchangeTimeout, id, 'private');

//bind all functions to allow destructuring
this.addContextListener = this.addContextListener.bind(this);
this.addEventListener = this.addEventListener.bind(this);
this.disconnect = this.disconnect.bind(this);
}

async addEventListener(type: PrivateChannelEventTypes | null, handler: EventHandler): Promise<Listener> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ export class DefaultIntentResolution implements IntentResolution {
this.result = result;
this.source = source;
this.intent = intent;

//bind all functions to allow destructuring
this.getResult = this.getResult.bind(this);
}

getResult(): Promise<IntentResult> {
Expand Down
37 changes: 36 additions & 1 deletion packages/fdc3-agent-proxy/test/features/app-channels.feature
Original file line number Diff line number Diff line change
Expand Up @@ -78,4 +78,39 @@ Feature: Channel Listeners Support
And I call "{channel1}" with "addContextListener" with parameters "{true}" and "{resultHandler}"
Then "{result}" is an error
And I call "{channel1}" with "addContextListener" with parameters "{null}" and "{true}"
Then "{result}" is an error
Then "{result}" is an error

Scenario: Destructured channel methods - broadcast and addContextListener
When I call "{api1}" with "getOrCreateChannel" with parameter "channel-name"
And I refer to "{result}" as "channel1"
And I destructure methods "addContextListener", "broadcast" from "{channel1}"
And I call destructured "addContextListener" with parameters "fdc3.instrument" and "{resultHandler}"
And messaging receives "{instrumentMessageOne}"
Then "{contexts}" is an array of objects with the following contents
| id.ticker | type | name |
| AAPL | fdc3.instrument | Apple |
And messaging will have posts
| payload.channelId | payload.contextType | matches_type |
| channel-name | {null} | getOrCreateChannelRequest |
| channel-name | fdc3.instrument | addContextListenerRequest |

Scenario: Destructured getCurrentContext after broadcast
When I call "{api1}" with "getOrCreateChannel" with parameter "channel-name"
And I refer to "{result}" as "channel1"
And I destructure methods "broadcast", "getCurrentContext" from "{channel1}"
And I call destructured "broadcast" with parameter "{instrumentContext}"
And I call destructured "getCurrentContext" with parameter "fdc3.instrument"
Then "{result}" is an object with the following contents
| id.ticker | type | name |
| AAPL | fdc3.instrument | Apple |

Scenario: Destructured listener receives filtered context
Given "countryContext" is a "fdc3.country" context
When I call "{api1}" with "getOrCreateChannel" with parameter "channel-name"
And I refer to "{result}" as "channel1"
And I destructure methods "addContextListener", "broadcast" from "{channel1}"
And I call destructured "addContextListener" with parameters "fdc3.instrument" and "{resultHandler}"
And messaging receives "{instrumentMessageOne}"
Then "{contexts}" is an array of objects with the following contents
| id.ticker | type | name |
| AAPL | fdc3.instrument | Apple |
49 changes: 49 additions & 0 deletions packages/fdc3-agent-proxy/test/features/intent-results.feature
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,52 @@ Feature: Intents Can Return Different Results
And messaging will have posts
| payload.intent | payload.context.type | payload.context.id.ticker | matches_type |
| OrderFood | fdc3.instrument | AAPL | raiseIntentRequest |

Scenario: Destructured getResult returns context data
Given Raise Intent returns a context of "{instrumentContext}"
When I destructure method "raiseIntent" from "{api}"
And I call destructured "raiseIntent" with parameters "OrderFood" and "{instrumentContext}"
And I destructure method "getResult" from "{result}"
And I call destructured "getResult"
Then "{result}" is an object with the following contents
| type | name |
| fdc3.instrument | Apple |
And messaging will have posts
| payload.intent | payload.context.type | payload.context.id.ticker | matches_type |
| OrderFood | fdc3.instrument | AAPL | raiseIntentRequest |

Scenario: Destructured raiseIntent with app parameter
When I destructure method "raiseIntent" from "{api}"
And I call destructured "raiseIntent" with parameters "OrderFood" and "{instrumentContext}" and "{c1}"
Then "{result}" is an object with the following contents
| source.appId | source.instanceId | intent |
| chipShop | c1 | OrderFood |
And messaging will have posts
| payload.intent | payload.context.type | payload.context.id.ticker | payload.app.appId | payload.app.instanceId | matches_type |
| OrderFood | fdc3.instrument | AAPL | chipShop | c1 | raiseIntentRequest |

Scenario: Destructured getResult returns app channel
Given Raise Intent returns an app channel
When I destructure method "raiseIntent" from "{api}"
And I call destructured "raiseIntent" with parameters "OrderFood" and "{instrumentContext}"
And I destructure method "getResult" from "{result}"
And I call destructured "getResult"
Then "{result}" is an object with the following contents
| type | id |
| app | result-channel |
And messaging will have posts
| payload.intent | payload.context.type | payload.context.id.ticker | matches_type |
| OrderFood | fdc3.instrument | AAPL | raiseIntentRequest |

Scenario: Destructured getResult returns private channel
Given Raise Intent returns a private channel
When I destructure method "raiseIntent" from "{api}"
And I call destructured "raiseIntent" with parameters "OrderFood" and "{instrumentContext}"
And I destructure method "getResult" from "{result}"
And I call destructured "getResult"
Then "{result}" is an object with the following contents
| type | id |
| private | result-channel |
And messaging will have posts
| payload.intent | payload.context.type | payload.context.id.ticker | matches_type |
| OrderFood | fdc3.instrument | AAPL | raiseIntentRequest |
20 changes: 20 additions & 0 deletions packages/fdc3-agent-proxy/test/features/open.feature
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,23 @@ Feature: Desktop Agent Information
And messaging will have posts
| payload.app.appId | payload.context.type | payload.context.id.ticker | matches_type |
| nonExistent | fdc3.instrument | AAPL | openRequest |

Scenario: Open An App - Destructured
When I destructure method "open" from "{api}"
And I call destructured "open" with parameters "{c1}" and "{instrumentContext}"
Then "{result}" is an object with the following contents
| appId | instanceId |
| chipShop | abc123 |
And messaging will have posts
| payload.app.appId | payload.context.type | payload.context.id.ticker | matches_type |
| chipShop | fdc3.instrument | AAPL | openRequest |

Scenario: Open An App Using App ID - Destructured
When I destructure method "open" from "{api}"
And I call destructured "open" with parameters "chipShop" and "{instrumentContext}"
Then "{result}" is an object with the following contents
| appId | instanceId |
| chipShop | abc123 |
And messaging will have posts
| payload.app.appId | payload.context.type | payload.context.id.ticker | matches_type |
| chipShop | fdc3.instrument | AAPL | openRequest |
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,28 @@ Feature: Basic Private Channels Support
| payload.channelId | matches_type |
| {null} | createPrivateChannelRequest |
| {privateChannel.id} | privateChannelDisconnectRequest |

Scenario: Destructured createPrivateChannel works correctly
When I destructure method "createPrivateChannel" from "{api}"
And I call destructured "createPrivateChannel"
And I refer to "{result}" as "destructuredPrivateChannel"
Then messaging will have posts
| payload.channelId | matches_type |
| {null} | createPrivateChannelRequest |

Scenario: Destructured private channel methods work correctly
Given "resultHandler" pipes context to "contexts"
And I destructure methods "addContextListener", "broadcast" from "{privateChannel}"
And I call destructured "addContextListener" with parameters "fdc3.instrument" and "{resultHandler}"
And I call destructured "broadcast" with parameter "{instrumentContext}"
And messaging receives "{instrumentMessageOne}"
Then "{contexts}" is an array of objects with the following contents
| id.ticker | type | name |
| AAPL | fdc3.instrument | Apple |

Scenario: Destructured disconnect works correctly
When I destructure method "disconnect" from "{privateChannel}"
And I call destructured "disconnect"
Then messaging will have posts
| payload.channelId | matches_type |
| {privateChannel.id} | privateChannelDisconnectRequest |
65 changes: 65 additions & 0 deletions packages/fdc3-agent-proxy/test/features/user-channels.feature
Original file line number Diff line number Diff line change
Expand Up @@ -235,3 +235,68 @@ Feature: Basic User Channels Support
Given "typesHandler" pipes events to "types"
When I call "{api}" with "addEventListener" with parameters "unknownEventType" and "{typesHandler}"
Then "{result}" is an error with message "UnknownEventType"

Scenario: Destructured getUserChannels returns user channels
When I destructure method "getUserChannels" from "{api}"
And I call destructured "getUserChannels"
Then "{result}" is an array of objects with the following contents
| id | type | displayMetadata.color | displayMetadata.glyph | displayMetadata.name |
| one | user | red | triangle | The one channel |
| two | user | red | triangle | The two channel |
| three | user | red | triangle | The three channel |
And messaging will have posts
| meta.source.appId | meta.source.instanceId | matches_type |
| cucumber-app | cucumber-instance | getUserChannelsRequest |

Scenario: Destructured joinUserChannel and getCurrentChannel work correctly
When I destructure method "joinUserChannel" from "{api}"
And I call destructured "joinUserChannel" with parameter "one"
And I destructure method "getCurrentChannel" from "{api}"
And I call destructured "getCurrentChannel"
Then "{result}" is an object with the following contents
| id | type | displayMetadata.color |
| one | user | red |
And messaging will have posts
| payload.channelId | matches_type |
| one | joinUserChannelRequest |
| {null} | getCurrentChannelRequest |

Scenario: Destructured channel getCurrentContext after broadcast
Given "resultHandler" pipes context to "contexts"
When I call "{api}" with "joinUserChannel" with parameter "one"
And I call "{api}" with "getCurrentChannel"
And I refer to "{result}" as "theChannel"
And I destructure methods "broadcast", "getCurrentContext" from "{api}"
And I destructure method "getCurrentContext" from "{theChannel}"
And I call destructured "broadcast" with parameter "{instrumentContext}"
And I call destructured "getCurrentContext"
Then "{result}" is an object with the following contents
| id.ticker | type | name |
| AAPL | fdc3.instrument | Apple |

Scenario: Destructured broadcast on user channel
Comment thread
kriswest marked this conversation as resolved.
Given "resultHandler" pipes context to "contexts"
When I destructure method "broadcast" from "{api}"
And I call "{api}" with "joinUserChannel" with parameter "one"
And I call destructured "broadcast" with parameter "{instrumentContext}"
And I call "{api}" with "getCurrentChannel"
And I refer to "{result}" as "theChannel"
And I call "{theChannel}" with "getCurrentContext"
Then "{result}" is an object with the following contents
| id.ticker | type | name |
| AAPL | fdc3.instrument | Apple |

Scenario: Destructured user channel addContextListener works correctly
Given "resultHandler" pipes context to "contexts"
When I destructure method "addContextListener" from "{api}"
And I call "{api}" with "joinUserChannel" with parameter "one"
And I call destructured "addContextListener" with parameters "fdc3.instrument" and "{resultHandler}"
And messaging receives "{instrumentMessageOne}"
Then "{contexts}" is an array of objects with the following contents
| id.ticker | type | name |
| AAPL | fdc3.instrument | Apple |
And messaging will have posts
| payload.channelId | payload.contextType | matches_type |
| one | {null} | joinUserChannelRequest |
| {null} | {null} | getCurrentChannelRequest |
| one | fdc3.instrument | addContextListenerRequest |
Original file line number Diff line number Diff line change
Expand Up @@ -209,3 +209,80 @@ Given('User Channels one, two and three', function (this: CustomWorld) {
three: [],
};
});

When(
'I destructure methods {string}, {string} from {string}',
function (this: CustomWorld, method1: string, method2: string, objectField: string) {
const object = handleResolve(objectField, this);
this.props[`destructured_${method1}`] = object[method1];
this.props[`destructured_${method2}`] = object[method2];
}
);

When(
'I destructure method {string} from {string}',
function (this: CustomWorld, methodName: string, objectField: string) {
const object = handleResolve(objectField, this);
const destructuredMethod = object[methodName];
this.props[`destructured_${methodName}`] = destructuredMethod;
}
);

When('I call destructured {string}', async function (this: CustomWorld, methodName: string) {
const destructuredMethod = this.props[`destructured_${methodName}`];
try {
const result = await destructuredMethod();
this.props['result'] = result;
} catch (error) {
this.props['error'] = error;
this.props['result'] = null;
}
});

When(
'I call destructured {string} with parameter {string}',
async function (this: CustomWorld, methodName: string, param: string) {
const destructuredMethod = this.props[`destructured_${methodName}`];
const resolvedParam = handleResolve(param, this);
try {
const result = await destructuredMethod(resolvedParam);
this.props['result'] = result;
} catch (error) {
this.props['error'] = error;
this.props['result'] = null;
}
}
);

When(
'I call destructured {string} with parameters {string} and {string}',
async function (this: CustomWorld, methodName: string, param1: string, param2: string) {
const destructuredMethod = this.props[`destructured_${methodName}`];
const resolvedParam1 = handleResolve(param1, this);
const resolvedParam2 = handleResolve(param2, this);
try {
const result = await destructuredMethod(resolvedParam1, resolvedParam2);
this.props['result'] = result;
} catch (error) {
this.props['error'] = error;
this.props['result'] = null;
}
}
);

When(
'I call destructured {string} with parameters {string} and {string} and {string}',
async function (this: CustomWorld, methodName: string, param1: string, param2: string, param3: string) {
const destructuredMethod = this.props[`destructured_${methodName}`];
const resolvedParam1 = handleResolve(param1, this);
const resolvedParam2 = handleResolve(param2, this);
const resolvedParam3 = handleResolve(param3, this);
try {
const result = await destructuredMethod(resolvedParam1, resolvedParam2, resolvedParam3);
this.props['result'] = result;
} catch (error) {
this.props['error'] = error;
this.props['result'] = null;
}
}
);
Loading
Loading