/** * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. */ import { ActionArgument, ActionTypes, ActionBase, ActionPayload, TextPayload, IActionArgument, TextAction, CardAction, ApiAction, CardPayload } from './Action' const createEmptyAction = (): ActionBase => ({ actionId: '', createdDateTime: '', payload: '', isTerminal: false, requiredEntitiesFromPayload: [], requiredEntities: [], requiredConditions: [], negativeEntities: [], negativeConditions: [], suggestedEntity: '', version: 0, packageCreationId: 0, packageDeletionId: 0, actionType: ActionTypes.TEXT, entityId: undefined, enumValueId: undefined, }) const expectedSimpleTextPayload = 'simple text payload' const textPayloadWithNoEntities: TextPayload = { json: { kind: 'value', document: { kind: 'document', data: {}, nodes: [ { kind: 'block', type: 'line', isVoid: false, data: {}, nodes: [ { kind: 'text', leaves: [ { kind: 'leaf', text: expectedSimpleTextPayload, marks: [] } ] } ] } ] } } } const textPayloadWithRequiredEntity: TextPayload = { json: { kind: 'value', document: { kind: 'document', data: {}, nodes: [ { kind: 'block', type: 'line', isVoid: false, data: {}, nodes: [ { kind: 'text', leaves: [ { kind: 'leaf', text: 'The value of custom is: ', marks: [] } ] }, { kind: 'inline', type: 'mention-inline-node', isVoid: false, data: { completed: true, option: { id: '627a43be-4675-4b98-84a7-537262561be6', name: 'custom' } }, nodes: [ { kind: 'text', leaves: [ { kind: 'leaf', text: '$custom', marks: [] } ] } ] }, { kind: 'text', leaves: [ { kind: 'leaf', text: '', marks: [] } ] } ] } ] } } } const textAction1: ActionBase = { ...createEmptyAction(), actionType: ActionTypes.TEXT, payload: JSON.stringify(textPayloadWithNoEntities) } const textAction2: ActionBase = { ...createEmptyAction(), actionType: ActionTypes.TEXT, payload: JSON.stringify(textPayloadWithRequiredEntity) } const expectedCardPayloadValue = 'customTemplateName' const cardActionArguments: IActionArgument[] = [ { parameter: 'p1', value: textPayloadWithNoEntities }, { parameter: 'p2', value: { json: {} } } ] const expectedCardActionArguments = cardActionArguments.map(aa => new ActionArgument(aa)) const cardAction: ActionBase = { ...createEmptyAction(), actionType: ActionTypes.CARD, payload: JSON.stringify({ payload: expectedCardPayloadValue, arguments: cardActionArguments } as CardPayload) } const expectedApiPayloadValue = 'myCallback' const apiAction: ActionBase = { ...createEmptyAction(), actionType: ActionTypes.API_LOCAL, payload: JSON.stringify({ payload: expectedApiPayloadValue, logicArguments: [ { parameter: 'p1', value: textPayloadWithNoEntities }, { parameter: 'p2', value: { json: {} } } ], renderArguments: [ { parameter: 'p1', value: textPayloadWithNoEntities }, { parameter: 'p2', value: { json: {} } } ] } as ActionPayload) } describe('Action', () => { describe('ActionBase', () => { test('given object representing action should assign all properties to object', () => { // Arrange const actionLikeObject: ActionBase = { actionId: 'fake-action-id', actionType: ActionTypes.TEXT, createdDateTime: new Date().toJSON(), payload: 'fake-action-payload', isTerminal: false, requiredEntitiesFromPayload: [], requiredEntities: [], negativeEntities: [], requiredConditions: [], negativeConditions: [], suggestedEntity: 'fake-action', version: 1, packageCreationId: 1, packageDeletionId: 0, entityId: undefined, enumValueId: undefined, } // Act const action = new ActionBase(actionLikeObject) // Assert expect(action.actionId).toEqual(actionLikeObject.actionId) }) }) describe('GetPayload', () => { test('given action with invalid payload, should throw exception when attempting to parse it as JSON', () => { // Arrange const corruptAction = new ActionBase({ actionId: 'fake-action-id', actionType: ActionTypes.TEXT, createdDateTime: new Date().toJSON(), payload: 'fake-action-payload', isTerminal: false, requiredEntitiesFromPayload: [], requiredEntities: [], requiredConditions: [], negativeEntities: [], negativeConditions: [], suggestedEntity: 'fake-action', version: 1, packageCreationId: 1, packageDeletionId: 0, entityId: undefined, enumValueId: undefined, }) // Act const thrower = () => ActionBase.GetPayload(corruptAction, new Map()) // Assert expect(thrower).toThrowError() }) test(`given action with unknown type return raw payload since we don't reliably know how to parse it`, () => { // Arrange const unknownAction = new ActionBase({ actionId: 'fake-action-id', actionType: 'fake-action-type' as ActionTypes, createdDateTime: new Date().toJSON(), payload: 'fake-action-payload', isTerminal: false, requiredEntitiesFromPayload: [], requiredEntities: [], requiredConditions: [], negativeEntities: [], negativeConditions: [], suggestedEntity: 'fake-action', version: 1, packageCreationId: 1, packageDeletionId: 0, entityId: undefined, enumValueId: undefined, }) // Act const payload = ActionBase.GetPayload(unknownAction, new Map()) // Assert expect(payload).toEqual(unknownAction.payload) }) test('given text action should return the plain text string', () => { // Act const actualTextPayloadValue = ActionBase.GetPayload(textAction1, new Map()) // Assert expect(actualTextPayloadValue).toEqual('simple text payload') }) test('given text action containing entity reference should return the plain text string with value replaced', () => { // Act const actualTextPayloadValue = ActionBase.GetPayload( textAction2, new Map([['627a43be-4675-4b98-84a7-537262561be6', 'customValue']]) ) // Assert expect(actualTextPayloadValue).toEqual('The value of custom is: customValue') }) test('given card action should return card template name', () => { // Act const actualCardPayloadValue = ActionBase.GetPayload(cardAction, new Map()) // Assert expect(actualCardPayloadValue).toEqual(expectedCardPayloadValue) }) test('given api action should return callback name', () => { // Act const actualApiPayloadValue = ActionBase.GetPayload(apiAction, new Map()) // Assert expect(actualApiPayloadValue).toEqual(expectedApiPayloadValue) }) }) describe('GetActionArguments', () => { test('given text action should return empty array because text actions do not have arguments', () => { // Act const actionArguments = ActionBase.GetActionArguments(textAction1) // Assert expect(actionArguments).toEqual([]) }) test('given card action or api action should return arguments', () => { // Act const actionArguments = ActionBase.GetActionArguments(cardAction) // Assert expect(actionArguments).toEqual(expectedCardActionArguments) }) }) describe('ActionArgument', () => { test('given action argument render it with given entity values', () => { const actionArguments = ActionBase.GetActionArguments(cardAction) const renderedValue = actionArguments[0].renderValue(new Map()) expect(renderedValue).toContain(expectedSimpleTextPayload) }) }) describe('TextAction', () => { test('given action without text type throw exception during construction', () => { const thrower = () => new TextAction(cardAction) expect(thrower).toThrowError() }) test('given action with text type should parse payload and assign to value', () => { const textAction = new TextAction(textAction1) expect(textAction.value).toBeDefined() }) test(`given text action render it's value`, () => { const textAction = new TextAction(textAction1) const renderedValue = textAction.renderValue(new Map()) expect(renderedValue).toContain(expectedSimpleTextPayload) }) test(`given text action render it's value with options`, () => { const textAction = new TextAction(textAction1) const renderedValue = textAction.renderValue(new Map(), { fallbackToOriginal: true }) expect(renderedValue).toContain(expectedSimpleTextPayload) }) }) describe('CardAction', () => { test('given action with type mismatch throw exception during construction', () => { const thrower = () => new CardAction(textAction1) expect(thrower).toThrowError() }) test('given action with card type should parse payload and extract templateName and arguments', () => { const action = new CardAction(cardAction) expect(action.templateName).toBeDefined() expect(action.arguments).toBeDefined() }) test(`given card action render it's value`, () => { const action = new CardAction(cardAction) const renderedArguments = action.renderArguments(new Map()) expect(renderedArguments[0].value).toEqual(expectedSimpleTextPayload) }) test(`given card action render it's value with options`, () => { const action = new CardAction(cardAction) const renderedArguments = action.renderArguments(new Map(), { fallbackToOriginal: true }) expect(renderedArguments[0].value).toEqual(expectedSimpleTextPayload) }) }) describe('ApiAction', () => { test('given action with type mismatch throw exception during construction', () => { const thrower = () => new ApiAction(textAction1) expect(thrower).toThrowError() }) test('given action with api type should parse payload and extract name and arguments', () => { const action = new ApiAction(apiAction) expect(action.name).toBeDefined() expect(action.logicArguments).toBeDefined() expect(action.renderArguments).toBeDefined() }) test(`given api action render it's arguments`, () => { const action = new ApiAction(apiAction) const renderedLogicArguments = action.renderLogicArguments(new Map()) const renderedRenderArguments = action.renderRenderArguments(new Map()) expect(renderedLogicArguments[0].value).toEqual(expectedSimpleTextPayload) expect(renderedRenderArguments[0].value).toEqual(expectedSimpleTextPayload) }) test(`given api action render it's value with options`, () => { const action = new ApiAction(apiAction) const renderedLogicArguments = action.renderLogicArguments(new Map(), { fallbackToOriginal: true }) const renderedRenderArguments = action.renderRenderArguments(new Map(), { fallbackToOriginal: true }) expect(renderedLogicArguments[0].value).toEqual(expectedSimpleTextPayload) expect(renderedRenderArguments[0].value).toEqual(expectedSimpleTextPayload) }) }) })