From a4f12a1a7ece5291ffc0cc96fdf9431ce3680369 Mon Sep 17 00:00:00 2001 From: Will Barnett Date: Tue, 19 Mar 2024 08:25:38 +0000 Subject: [PATCH 1/9] EducationPlatform testing, added tests for convert and convert convertIncludingMetamodel --- .../test/spec/testEducationPlatformAppSpec.js | 135 +++++++++++++++++- 1 file changed, 134 insertions(+), 1 deletion(-) diff --git a/platform/test/spec/testEducationPlatformAppSpec.js b/platform/test/spec/testEducationPlatformAppSpec.js index 169e8d2..01b0206 100644 --- a/platform/test/spec/testEducationPlatformAppSpec.js +++ b/platform/test/spec/testEducationPlatformAppSpec.js @@ -148,7 +148,7 @@ describe("EducationPlatformApp", () => { const PARAM2_VALUE = "param2's contents"; const PARAM2_CONVERTED_VALUE = "param2's converted contents"; - // types the test action functions are exepecting + // types the test action functions are expecting const ACTION_FUNCTION_PARAM1_TYPE = "type1"; const ACTION_FUNCTION_PARAM2_TYPE = "type2"; const ACTION_FUNCTION_RESULT= "Test function result"; @@ -329,6 +329,139 @@ describe("EducationPlatformApp", () => { }) + describe("convert", () => { + let platform; + let findConversionSpy; + + const FILE_CONTENTS = "Test file contents."; + const SOURCE_TYPE = "test-source-type"; + const TARGET_TYPE = "test-target-type"; + const PARAM_NAME = "test"; + const callConversionReturn = new Promise(function(resolve) { + resolve(true); + }) + + const CONVERSION_FUNCTION_ID = "conversion-function-id"; + + beforeEach(()=>{ + // Setup + findConversionSpy = spyOn( EducationPlatform.prototype, "functionRegistry_find"). + and.returnValue(CONVERSION_FUNCTION_ID); + + spyOn( EducationPlatform.prototype, "functionRegistry_callConversion").and.returnValue( + callConversionReturn); + + spyOn( EducationPlatform.prototype, "errorNotification"); + + platform = new EducationPlatform(); + + }) + + it("calls functionRegistry_callConversion on a conversion function being available", ()=>{ + // Call the target object + platform.convert(FILE_CONTENTS, SOURCE_TYPE, TARGET_TYPE, PARAM_NAME); + + // Check the expected results + expect(platform.functionRegistry_callConversion).toHaveBeenCalledWith( + CONVERSION_FUNCTION_ID, { [SOURCE_TYPE]: FILE_CONTENTS } , PARAM_NAME + ); + + expect(platform.errorNotification).not.toHaveBeenCalled(); + }) + + it("returns a promise on a conversion function being available", ()=>{ + // Call the target object + const convertResult = platform.convert(FILE_CONTENTS, SOURCE_TYPE, TARGET_TYPE, PARAM_NAME); + + // Check the expected results + expect(convertResult).toEqual(callConversionReturn); + }) + + it("returns null and provides an error notification on a conversion function not being available", ()=>{ + findConversionSpy.and.returnValue(null); + + // Call the target object + const convertResult = platform.convert(FILE_CONTENTS, SOURCE_TYPE, TARGET_TYPE, PARAM_NAME); + + // Check the expected results + expect(convertResult).toEqual(null); + expect(platform.errorNotification).toHaveBeenCalledWith(jasmine.stringMatching("(N|n)o conversion function")) + }) + + }) + + describe("convertIncludingMetamodel", () => { + let platform; + let findConversionSpy; + + const FILE_CONTENTS = "Test file contents."; + const SOURCE_TYPE = "test-source-type"; + const TARGET_TYPE = "test-target-type"; + const MM_FILE_CONTENTS = "Test metamodel file contents." + const MM_TYPE = "test-metamodel-type"; + const PARAM_NAME = "test"; + const callConversionReturn = new Promise(function(resolve) { + resolve(true); + }) + + const CONVERSION_FUNCTION_ID = "conversion-function-id"; + + beforeEach(()=>{ + // Setup + findConversionSpy = spyOn( EducationPlatform.prototype, "functionRegistry_findPartial"). + and.returnValue([CONVERSION_FUNCTION_ID]); + + spyOn( EducationPlatform.prototype, "functionRegistry_callConversion").and.returnValue( + callConversionReturn); + + spyOn( EducationPlatform.prototype, "errorNotification"); + + platform = new EducationPlatform(); + + // platform - toolsManager + let toolsManagerSpy = jasmine.createSpyObj(['getActionFunction']); + toolsManagerSpy.getActionFunction.and.returnValue(new ActionFunction({ + parameters: [ + {name: "input", type: SOURCE_TYPE, instanceOf: "metamodel"}, + {name: "metamodel", type: MM_TYPE} + ] + })); + platform.toolsManager= toolsManagerSpy; + + }) + + it("calls functionRegistry_callConversion on a conversion function being available", async ()=>{ + // Call the target object + await platform.convertIncludingMetamodel(FILE_CONTENTS, SOURCE_TYPE, MM_FILE_CONTENTS, MM_TYPE, TARGET_TYPE, PARAM_NAME); + + // Check the expected results + expect(platform.functionRegistry_callConversion).toHaveBeenCalledWith( + CONVERSION_FUNCTION_ID, {[SOURCE_TYPE]: FILE_CONTENTS, [MM_TYPE]: MM_FILE_CONTENTS } , PARAM_NAME + ); + + expect(platform.errorNotification).not.toHaveBeenCalled(); + }) + + it("returns a promise on a conversion function being available", async ()=>{ + // Call the target object + const convertResult = platform.convertIncludingMetamodel(FILE_CONTENTS, SOURCE_TYPE, MM_FILE_CONTENTS, MM_TYPE, TARGET_TYPE, PARAM_NAME); + + // Check the expected results + await expectAsync(convertResult).toBePending(); + }) + + it("returns null and provides an error notification on a conversion function not being available", async ()=>{ + findConversionSpy.and.returnValue(null); + + // Call the target object + const convertResult = await platform.convertIncludingMetamodel(FILE_CONTENTS, SOURCE_TYPE, MM_FILE_CONTENTS, MM_TYPE, TARGET_TYPE, PARAM_NAME); + + // Check the expected results + expect(convertResult).toEqual(null); + expect(platform.errorNotification).toHaveBeenCalledWith(jasmine.stringMatching("(N|n)o conversion function")) + }) + + }) describe("notification()", () => { let platform; From 45e7287d9f7e47ce38ee9f016e56e7681aa0ae5f Mon Sep 17 00:00:00 2001 From: Will Barnett Date: Tue, 19 Mar 2024 08:36:16 +0000 Subject: [PATCH 2/9] Added defensive check for selectConversionFunctionConvertMetamodel()'s conversionFunctions parameter. --- platform/src/EducationPlatformApp.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/platform/src/EducationPlatformApp.js b/platform/src/EducationPlatformApp.js index bb54df0..8b1309a 100644 --- a/platform/src/EducationPlatformApp.js +++ b/platform/src/EducationPlatformApp.js @@ -1,4 +1,4 @@ -/*global $ -- jquery is externally imported*/ +/*global $ -- jquery is exterally imported*/ /*global FEEDBACK_SURVEY_URL -- is set by environment variable*/ /*global Metro -- Metro is externally imported*/ @@ -608,7 +608,11 @@ class EducationPlatformApp { */ async selectConversionFunctionConvertMetamodel(metamodelType, metamodelValue, conversionFunctions, convertMetamodel, parameterName, typeValueMap){ let conversionFunctionId; - let functionsToCheck = [...conversionFunctions] + let functionsToCheck = []; + + if (Array.isArray(conversionFunctions)){ + functionsToCheck = [...conversionFunctions]; + } while ( conversionFunctionId==null && functionsToCheck.length > 0){ let functionId = functionsToCheck.pop(); From 92006f013624654aeaadb7525be01987bbf67426 Mon Sep 17 00:00:00 2001 From: Will Barnett Date: Tue, 19 Mar 2024 18:07:14 +0000 Subject: [PATCH 3/9] EducationPlatform testing, added tests for selectConversionFunctionConvertMetamodel() and fix for it to return null when no conversion found. --- platform/src/EducationPlatformApp.js | 2 +- .../test/spec/testEducationPlatformAppSpec.js | 290 +++++++++++++++++- 2 files changed, 276 insertions(+), 16 deletions(-) diff --git a/platform/src/EducationPlatformApp.js b/platform/src/EducationPlatformApp.js index 8b1309a..2a98685 100644 --- a/platform/src/EducationPlatformApp.js +++ b/platform/src/EducationPlatformApp.js @@ -607,7 +607,7 @@ class EducationPlatformApp { * @returns {string} the id of a conversion function to use, null if none found. */ async selectConversionFunctionConvertMetamodel(metamodelType, metamodelValue, conversionFunctions, convertMetamodel, parameterName, typeValueMap){ - let conversionFunctionId; + let conversionFunctionId = null; let functionsToCheck = []; if (Array.isArray(conversionFunctions)){ diff --git a/platform/test/spec/testEducationPlatformAppSpec.js b/platform/test/spec/testEducationPlatformAppSpec.js index 01b0206..dffc092 100644 --- a/platform/test/spec/testEducationPlatformAppSpec.js +++ b/platform/test/spec/testEducationPlatformAppSpec.js @@ -329,7 +329,7 @@ describe("EducationPlatformApp", () => { }) - describe("convert", () => { + describe("convert()", () => { let platform; let findConversionSpy; @@ -345,15 +345,15 @@ describe("EducationPlatformApp", () => { beforeEach(()=>{ // Setup - findConversionSpy = spyOn( EducationPlatform.prototype, "functionRegistry_find"). + findConversionSpy = spyOn( EducationPlatformApp.prototype, "functionRegistry_find"). and.returnValue(CONVERSION_FUNCTION_ID); - spyOn( EducationPlatform.prototype, "functionRegistry_callConversion").and.returnValue( + spyOn( EducationPlatformApp.prototype, "functionRegistry_callConversion").and.returnValue( callConversionReturn); - spyOn( EducationPlatform.prototype, "errorNotification"); + spyOn( EducationPlatformApp.prototype, "errorNotification"); - platform = new EducationPlatform(); + platform = new EducationPlatformApp(); }) @@ -369,7 +369,7 @@ describe("EducationPlatformApp", () => { expect(platform.errorNotification).not.toHaveBeenCalled(); }) - it("returns a promise on a conversion function being available", ()=>{ + it("returns a promise on a conversion function being available", ()=> { // Call the target object const convertResult = platform.convert(FILE_CONTENTS, SOURCE_TYPE, TARGET_TYPE, PARAM_NAME); @@ -377,7 +377,7 @@ describe("EducationPlatformApp", () => { expect(convertResult).toEqual(callConversionReturn); }) - it("returns null and provides an error notification on a conversion function not being available", ()=>{ + it("returns null and provides an error notification on a conversion function not being available", ()=> { findConversionSpy.and.returnValue(null); // Call the target object @@ -390,7 +390,7 @@ describe("EducationPlatformApp", () => { }) - describe("convertIncludingMetamodel", () => { + describe("convertIncludingMetamodel()", () => { let platform; let findConversionSpy; @@ -408,15 +408,15 @@ describe("EducationPlatformApp", () => { beforeEach(()=>{ // Setup - findConversionSpy = spyOn( EducationPlatform.prototype, "functionRegistry_findPartial"). + findConversionSpy = spyOn( EducationPlatformApp.prototype, "functionRegistry_findPartial"). and.returnValue([CONVERSION_FUNCTION_ID]); - spyOn( EducationPlatform.prototype, "functionRegistry_callConversion").and.returnValue( + spyOn( EducationPlatformApp.prototype, "functionRegistry_callConversion").and.returnValue( callConversionReturn); - spyOn( EducationPlatform.prototype, "errorNotification"); + spyOn( EducationPlatformApp.prototype, "errorNotification"); - platform = new EducationPlatform(); + platform = new EducationPlatformApp(); // platform - toolsManager let toolsManagerSpy = jasmine.createSpyObj(['getActionFunction']); @@ -430,7 +430,7 @@ describe("EducationPlatformApp", () => { }) - it("calls functionRegistry_callConversion on a conversion function being available", async ()=>{ + it("calls functionRegistry_callConversion on a conversion function being available", async ()=> { // Call the target object await platform.convertIncludingMetamodel(FILE_CONTENTS, SOURCE_TYPE, MM_FILE_CONTENTS, MM_TYPE, TARGET_TYPE, PARAM_NAME); @@ -442,7 +442,7 @@ describe("EducationPlatformApp", () => { expect(platform.errorNotification).not.toHaveBeenCalled(); }) - it("returns a promise on a conversion function being available", async ()=>{ + it("returns a promise on a conversion function being available", async () => { // Call the target object const convertResult = platform.convertIncludingMetamodel(FILE_CONTENTS, SOURCE_TYPE, MM_FILE_CONTENTS, MM_TYPE, TARGET_TYPE, PARAM_NAME); @@ -450,7 +450,7 @@ describe("EducationPlatformApp", () => { await expectAsync(convertResult).toBePending(); }) - it("returns null and provides an error notification on a conversion function not being available", async ()=>{ + it("returns null and provides an error notification on a conversion function not being available", async () => { findConversionSpy.and.returnValue(null); // Call the target object @@ -463,6 +463,266 @@ describe("EducationPlatformApp", () => { }) + describe("selectConversionFunctionConvertMetamodel()", () => { + let platform; + + const SOURCE_TYPE = "test-source-type"; + const FILE_CONTENTS = "Test file contents."; + const MM_FILE_CONTENTS = "Test metamodel file contents." + const MM_TARGET_TYPE = "test-metamodel-target-type"; + const PARAM_NAME = "test"; + + const CONVERSION_FUNCTION_ID = "conversion-function-id"; + const X_FUNCTION_ID = "x-function-id"; // Not interested + + let toolsManagerSpy; + + beforeEach( () => { + // Setup + spyOn( EducationPlatformApp.prototype, "errorNotification"); + + platform = new EducationPlatformApp(); + + // platform - toolsManager + toolsManagerSpy = jasmine.createSpyObj(['getActionFunction', 'getConversionFunction']); + + toolsManagerSpy.getActionFunction.and.callFake( (functionId) => { + let actionFunctionConfig; + + switch (functionId){ + case CONVERSION_FUNCTION_ID: + actionFunctionConfig = { + parameters: [ + {name: "input", type: SOURCE_TYPE, instanceOf: "metamodel"}, + {name: "metamodel", type: MM_TARGET_TYPE} + ] + }; + break; + + case X_FUNCTION_ID: + actionFunctionConfig = { + parameters: [ + {name: "input", type: SOURCE_TYPE, instanceOf: "metamodel"}, + {name: "metamodel", type: "X"} + ] + } + break; + default: + actionFunctionConfig = null; + } + + return new ActionFunction(actionFunctionConfig) + }) + platform.toolsManager = toolsManagerSpy; + + }) + + it("returns a function id if a conversion is possible without considering the metamodel", async () => { + const CONSIDER_MM = false; + let mm_type = MM_TARGET_TYPE; + const typeValueMap = { [SOURCE_TYPE]: FILE_CONTENTS } + + // Call the target object + let selectConversionResult = await platform.selectConversionFunctionConvertMetamodel(mm_type, MM_FILE_CONTENTS, [CONVERSION_FUNCTION_ID, X_FUNCTION_ID], CONSIDER_MM, PARAM_NAME, typeValueMap) + + // Check the expected results + expect(selectConversionResult).toEqual(CONVERSION_FUNCTION_ID); + }) + + it("returns null if a conversion is not possible without considering the metamodel", async () => { + const CONSIDER_MM = false; + let mm_type = MM_TARGET_TYPE; + const typeValueMap = { [SOURCE_TYPE]: FILE_CONTENTS } + + // Call the target object + let selectConversionResult = await platform.selectConversionFunctionConvertMetamodel(mm_type, MM_FILE_CONTENTS, [X_FUNCTION_ID, X_FUNCTION_ID], CONSIDER_MM, PARAM_NAME, typeValueMap) + + // Check the expected results + expect(selectConversionResult).toEqual(null); + }) + + it("returns a function id, converts the metamodel, and adds the converted metamodel value to the typeValueMap if a conversion is possible considering the metamodel", async ()=>{ + const CONSIDER_MM = true; + let mm_type = "test-metamodel-type"; + const typeValueMap = { [SOURCE_TYPE]: FILE_CONTENTS } + + const MM_CONVERSION_FUNCTION_ID = "metamodel-conversion-function-id"; + const MM_CONVERTED_CONTENTS = "Test converted metamodel contents."; + + const callConversionReturn = new Promise(function(resolve) { + resolve({data: MM_CONVERTED_CONTENTS}); + }) + spyOn( EducationPlatformApp.prototype, "functionRegistry_callConversion").and.returnValue( + callConversionReturn); + + toolsManagerSpy.getConversionFunction.and.returnValues(null, MM_CONVERSION_FUNCTION_ID); // Find possible conversion on the second call + + // Call the target object + let selectConversionResult = await platform.selectConversionFunctionConvertMetamodel(mm_type, MM_FILE_CONTENTS, [CONVERSION_FUNCTION_ID, X_FUNCTION_ID], CONSIDER_MM, PARAM_NAME, typeValueMap) + + // Check the expected results + expect(platform.functionRegistry_callConversion).toHaveBeenCalledWith( + MM_CONVERSION_FUNCTION_ID, { [mm_type]: MM_FILE_CONTENTS}, PARAM_NAME + ); + + expect(typeValueMap[MM_TARGET_TYPE]).toEqual(MM_CONVERTED_CONTENTS); + + expect(selectConversionResult).toEqual(CONVERSION_FUNCTION_ID); + }) + + it("returns null if no conversion is available considering the metamodel", async () => { + const CONSIDER_MM = true; + let mm_type = "test-metamodel-type"; + const typeValueMap = { [SOURCE_TYPE]: FILE_CONTENTS } + + spyOn( EducationPlatformApp.prototype, "functionRegistry_callConversion"); + + toolsManagerSpy.getConversionFunction.and.returnValues(null, null); // Do not find possible conversion + + // Call the target object + let selectConversionResult = await platform.selectConversionFunctionConvertMetamodel(mm_type, MM_FILE_CONTENTS, [CONVERSION_FUNCTION_ID, X_FUNCTION_ID], CONSIDER_MM, PARAM_NAME, typeValueMap) + + // Check the expected results + expect(platform.functionRegistry_callConversion).not.toHaveBeenCalled(); + + expect(typeValueMap[MM_TARGET_TYPE]).toEqual(undefined); + + expect(selectConversionResult).toEqual(null); + }) + }) + + + + describe("selectConversionFunctionConvertMetamodel()", () => { + let platform; + + const SOURCE_TYPE = "test-source-type"; + const FILE_CONTENTS = "Test file contents."; + const MM_FILE_CONTENTS = "Test metamodel file contents." + const MM_TARGET_TYPE = "test-metamodel-target-type"; + const PARAM_NAME = "test"; + + const CONVERSION_FUNCTION_ID = "conversion-function-id"; + const X_FUNCTION_ID = "x-function-id"; // Not interested + + let toolsManagerSpy; + + beforeEach( () => { + // Setup + spyOn( EducationPlatformApp.prototype, "errorNotification"); + + platform = new EducationPlatformApp(); + + // platform - toolsManager + toolsManagerSpy = jasmine.createSpyObj(['getActionFunction', 'getConversionFunction']); + + toolsManagerSpy.getActionFunction.and.callFake( (functionId) => { + let actionFunctionConfig; + + switch (functionId){ + case CONVERSION_FUNCTION_ID: + actionFunctionConfig = { + parameters: [ + {name: "input", type: SOURCE_TYPE, instanceOf: "metamodel"}, + {name: "metamodel", type: MM_TARGET_TYPE} + ] + }; + break; + + case X_FUNCTION_ID: + actionFunctionConfig = { + parameters: [ + {name: "input", type: SOURCE_TYPE, instanceOf: "metamodel"}, + {name: "metamodel", type: "X"} + ] + } + break; + default: + actionFunctionConfig = null; + } + + return new ActionFunction(actionFunctionConfig) + }) + platform.toolsManager = toolsManagerSpy; + + }) + + it("returns a function id if a conversion is possible without considering the metamodel", async () => { + const CONSIDER_MM = false; + let mm_type = MM_TARGET_TYPE; + const typeValueMap = { [SOURCE_TYPE]: FILE_CONTENTS } + + // Call the target object + let selectConversionResult = await platform.selectConversionFunctionConvertMetamodel(mm_type, MM_FILE_CONTENTS, [CONVERSION_FUNCTION_ID, X_FUNCTION_ID], CONSIDER_MM, PARAM_NAME, typeValueMap) + + // Check the expected results + expect(selectConversionResult).toEqual(CONVERSION_FUNCTION_ID); + }) + + it("returns null if a conversion is not possible without considering the metamodel", async () => { + const CONSIDER_MM = false; + let mm_type = MM_TARGET_TYPE; + const typeValueMap = { [SOURCE_TYPE]: FILE_CONTENTS } + + // Call the target object + let selectConversionResult = await platform.selectConversionFunctionConvertMetamodel(mm_type, MM_FILE_CONTENTS, [X_FUNCTION_ID, X_FUNCTION_ID], CONSIDER_MM, PARAM_NAME, typeValueMap) + + // Check the expected results + expect(selectConversionResult).toEqual(null); + }) + + it("returns a function id, converts the metamodel, and adds the converted metamodel value to the typeValueMap if a conversion is possible considering the metamodel", async ()=>{ + const CONSIDER_MM = true; + let mm_type = "test-metamodel-type"; + const typeValueMap = { [SOURCE_TYPE]: FILE_CONTENTS } + + const MM_CONVERSION_FUNCTION_ID = "metamodel-conversion-function-id"; + const MM_CONVERTED_CONTENTS = "Test converted metamodel contents."; + + const callConversionReturn = new Promise(function(resolve) { + resolve({data: MM_CONVERTED_CONTENTS}); + }) + spyOn( EducationPlatformApp.prototype, "functionRegistry_callConversion").and.returnValue( + callConversionReturn); + + toolsManagerSpy.getConversionFunction.and.returnValues(null, MM_CONVERSION_FUNCTION_ID); // Find possible conversion on the second call + + // Call the target object + let selectConversionResult = await platform.selectConversionFunctionConvertMetamodel(mm_type, MM_FILE_CONTENTS, [CONVERSION_FUNCTION_ID, X_FUNCTION_ID], CONSIDER_MM, PARAM_NAME, typeValueMap) + + // Check the expected results + expect(platform.functionRegistry_callConversion).toHaveBeenCalledWith( + MM_CONVERSION_FUNCTION_ID, { [mm_type]: MM_FILE_CONTENTS}, PARAM_NAME + ); + + expect(typeValueMap[MM_TARGET_TYPE]).toEqual(MM_CONVERTED_CONTENTS); + + expect(selectConversionResult).toEqual(CONVERSION_FUNCTION_ID); + }) + + it("returns null if no conversion is available considering the metamodel", async () => { + const CONSIDER_MM = true; + let mm_type = "test-metamodel-type"; + const typeValueMap = { [SOURCE_TYPE]: FILE_CONTENTS } + + spyOn( EducationPlatformApp.prototype, "functionRegistry_callConversion"); + + toolsManagerSpy.getConversionFunction.and.returnValues(null, null); // Do not find possible conversion + + // Call the target object + let selectConversionResult = await platform.selectConversionFunctionConvertMetamodel(mm_type, MM_FILE_CONTENTS, [CONVERSION_FUNCTION_ID, X_FUNCTION_ID], CONSIDER_MM, PARAM_NAME, typeValueMap) + + // Check the expected results + expect(platform.functionRegistry_callConversion).not.toHaveBeenCalled(); + + expect(typeValueMap[MM_TARGET_TYPE]).toEqual(undefined); + + expect(selectConversionResult).toEqual(null); + }) + }) + + + describe("notification()", () => { let platform; From 38c6c38c69fb75c81333fcb3bbccdb843983d2fc Mon Sep 17 00:00:00 2001 From: Will Barnett Date: Tue, 19 Mar 2024 21:55:24 +0000 Subject: [PATCH 4/9] EducationPlatform testing, added test for functionRegistry_call() --- .../test/spec/testEducationPlatformAppSpec.js | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/platform/test/spec/testEducationPlatformAppSpec.js b/platform/test/spec/testEducationPlatformAppSpec.js index dffc092..c36f9d3 100644 --- a/platform/test/spec/testEducationPlatformAppSpec.js +++ b/platform/test/spec/testEducationPlatformAppSpec.js @@ -6,6 +6,7 @@ export var TOKEN_SERVER_URL = "test://ts.url"; import {EducationPlatformApp} from "../../src/EducationPlatformApp.js"; import { ActionFunction } from "../../src/ActionFunction.js"; import { Panel } from "../../src/Panel.js"; +import "jasmine-ajax"; describe("EducationPlatformApp", () => { @@ -591,6 +592,63 @@ describe("EducationPlatformApp", () => { }) }) + describe("functionRegistry_call()", () => { + const TOOL_URL = "test://t1.url/toolfunction"; + const TOOL_RESPONSE = '{ "validationResult": "PASS", "output": "Test" }'; + const CONVERSION_FUNCTION_ID = "test-function-id"; + + const PARAMETER_1_NAME = "test-param-1"; + const PARAMETER_2_NAME = "language"; + + const PARAMETERS_INPUT = { + [PARAMETER_1_NAME]: "Parameter 1 value", + [PARAMETER_2_NAME]: "Parameter 2 value" + }; + + let platform; + + + beforeEach(()=>{ + // Setup + jasmine.Ajax.install(); + + platform = new EducationPlatform(); + + jasmine.Ajax.stubRequest(TOOL_URL).andReturn({ + "responseText": TOOL_RESPONSE, + "status": 200 + }); + + // platform - toolsManager + let toolsManagerSpy = jasmine.createSpyObj(['getActionFunction']); + toolsManagerSpy.getActionFunction.and.returnValue(new ActionFunction({ + path: TOOL_URL + })); + platform.toolsManager= toolsManagerSpy; + + }) + + afterEach(function() { + jasmine.Ajax.uninstall(); + }); + + it("returns the result via promise", async () => { + // Call the target object + const functionResponse = platform.functionRegistry_call(CONVERSION_FUNCTION_ID, PARAMETERS_INPUT); + + // Check the expected results + await expectAsync(functionResponse).toBeResolvedTo(TOOL_RESPONSE); + }) + + it("sends a request to the tool service url", async () => { + // Call the target object + platform.functionRegistry_call(CONVERSION_FUNCTION_ID, PARAMETERS_INPUT); + + // Check the expected results + const request = jasmine.Ajax.requests.mostRecent(); + expect(request.data()).toEqual( PARAMETERS_INPUT ); + }) + }) describe("selectConversionFunctionConvertMetamodel()", () => { From c49b664c0f77fe81c6be656874e240f7f923e6a5 Mon Sep 17 00:00:00 2001 From: Will Barnett Date: Tue, 19 Mar 2024 23:19:44 +0000 Subject: [PATCH 5/9] EducationPlatform testing, added test for jsonRequestConversion(). --- .../test/spec/testEducationPlatformAppSpec.js | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/platform/test/spec/testEducationPlatformAppSpec.js b/platform/test/spec/testEducationPlatformAppSpec.js index c36f9d3..d9f46c2 100644 --- a/platform/test/spec/testEducationPlatformAppSpec.js +++ b/platform/test/spec/testEducationPlatformAppSpec.js @@ -650,6 +650,80 @@ describe("EducationPlatformApp", () => { }) }) + describe("jsonRequestConversion()", () => { + const TOOL_URL = "test://t1.url/toolfunction"; + const CONVERSION_FUNCTION_ID = "test-function-id"; + const PARAMETER_NAME = "testParameter1"; + const TYPE_MODEL = "type-model"; + const TYPE_METAMODEL = "type-metamodel"; + const MODEL_CONTENTS = "Parameter 1 model value"; + const METAMODEL_CONTENTS = "Parameter 2 metamodel value"; + + const TYPE_MAP_INPUT = { + [TYPE_MODEL]: MODEL_CONTENTS, + [TYPE_METAMODEL]: METAMODEL_CONTENTS + }; + + const CONVERSION_PARAM_IN = "input"; + const CONVERSION_PARAM_MM = "metamodel"; + const CONVERTED_MODEL = "Converted model contents."; + const TOOL_RESPONSE = `{"output": "${CONVERTED_MODEL}"}`; + + let platform; + + + beforeEach(()=>{ + // Setup + jasmine.Ajax.install(); + + platform = new EducationPlatform(); + + // xhr + jasmine.Ajax.stubRequest(TOOL_URL).andReturn({ + "responseText": TOOL_RESPONSE, + "status": 200 + }); + + // platform - toolsManager + let toolsManagerSpy = jasmine.createSpyObj(['getActionFunction']); + toolsManagerSpy.getActionFunction.and.returnValue(new ActionFunction({ + parameters: [ + {name: CONVERSION_PARAM_IN, type: TYPE_MODEL, instanceOf: "metamodel"}, + {name: CONVERSION_PARAM_MM, type: TYPE_METAMODEL} + ], + path: TOOL_URL + })); + platform.toolsManager= toolsManagerSpy; + }) + + afterEach(function() { + jasmine.Ajax.uninstall(); + }); + + it("sends a request to the tool service url", async () => { + const EXPECTED_REQUEST = { + [CONVERSION_PARAM_IN]: MODEL_CONTENTS, + [CONVERSION_PARAM_MM]: METAMODEL_CONTENTS + } + + // Call the target object + platform.functionRegistry_callConversion(CONVERSION_FUNCTION_ID, TYPE_MAP_INPUT, PARAMETER_NAME); + + // Check the expected results + const request = jasmine.Ajax.requests.mostRecent(); + expect(request.data()).toEqual( EXPECTED_REQUEST ); + }) + + it("returns the converted result via a promise", async () => { + const EXPECTED_RESPONSE = { name: PARAMETER_NAME, data: CONVERTED_MODEL }; // Format given by utility jsonRequestConversion() + + // Call the target object + const conversionResponse = platform.functionRegistry_callConversion(CONVERSION_FUNCTION_ID, TYPE_MAP_INPUT, PARAMETER_NAME); + + // Check the expected results + await expectAsync(conversionResponse).toBeResolvedTo(EXPECTED_RESPONSE); + }) + }) describe("selectConversionFunctionConvertMetamodel()", () => { let platform; From 57357e266b283ca711beb89cb5088c4543a12dc1 Mon Sep 17 00:00:00 2001 From: Will Barnett Date: Thu, 21 Mar 2024 10:16:20 +0000 Subject: [PATCH 6/9] Renames to use the updated EducationPlatformApp class name following rebase. --- platform/test/spec/testEducationPlatformAppSpec.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/test/spec/testEducationPlatformAppSpec.js b/platform/test/spec/testEducationPlatformAppSpec.js index d9f46c2..59800d8 100644 --- a/platform/test/spec/testEducationPlatformAppSpec.js +++ b/platform/test/spec/testEducationPlatformAppSpec.js @@ -612,7 +612,7 @@ describe("EducationPlatformApp", () => { // Setup jasmine.Ajax.install(); - platform = new EducationPlatform(); + platform = new EducationPlatformApp(); jasmine.Ajax.stubRequest(TOOL_URL).andReturn({ "responseText": TOOL_RESPONSE, @@ -676,7 +676,7 @@ describe("EducationPlatformApp", () => { // Setup jasmine.Ajax.install(); - platform = new EducationPlatform(); + platform = new EducationPlatformApp(); // xhr jasmine.Ajax.stubRequest(TOOL_URL).andReturn({ From 061e78c503f0079d86bfd7a6fba25cf16489f6fa Mon Sep 17 00:00:00 2001 From: Will Barnett Date: Thu, 21 Mar 2024 11:46:34 +0000 Subject: [PATCH 7/9] Corrected typos in comments. --- platform/src/EducationPlatformApp.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/platform/src/EducationPlatformApp.js b/platform/src/EducationPlatformApp.js index 2a98685..dca1070 100644 --- a/platform/src/EducationPlatformApp.js +++ b/platform/src/EducationPlatformApp.js @@ -1,4 +1,4 @@ -/*global $ -- jquery is exterally imported*/ +/*global $ -- jquery is externally imported*/ /*global FEEDBACK_SURVEY_URL -- is set by environment variable*/ /*global Metro -- Metro is externally imported*/ @@ -276,7 +276,7 @@ class EducationPlatformApp { this.outputLanguage = this.activity.outputLanguage; } - // Create panels for the given activites + // Create panels for the given activities for ( let apanel of this.activity.panels ){ var newPanel = this.createPanelForDefinitionId(apanel); @@ -480,7 +480,7 @@ class EducationPlatformApp { } } - // Invoke the actionFunction on compeletion of any conversions + // Invoke the actionFunction on completion of any conversions let actionFunctionPromise = new Promise( (resolve, reject) => { Promise.all( parameterPromises ).then( (values) => { @@ -523,12 +523,12 @@ class EducationPlatformApp { * @param {string} sourceType * @param {string} targetType * @param {string} parameterName name of the parameter for request - * @returns {Promise} promise for the converted paramter value + * @returns {Promise} promise for the converted parameter value */ convert(sourceValue, sourceType, targetType, parameterName){ let parameterPromise; - let typesPanelValuesMap = {}; // Types have to be distinct for mapping to the conversion function's paramters + let typesPanelValuesMap = {}; // Types have to be distinct for mapping to the conversion function's parameters typesPanelValuesMap[sourceType]= sourceValue; let conversionFunctionId = this.functionRegistry_find( Object.keys(typesPanelValuesMap), targetType ); @@ -558,11 +558,11 @@ class EducationPlatformApp { * @param {string} metamodelType * @param {string} targetType * @param {string} parameterName name of the parameter for request - * @returns {Promise} promise for the converted paramter value + * @returns {Promise} promise for the converted parameter value */ async convertIncludingMetamodel(sourceValue, sourceType, metamodelValue, metamodelType, targetType, parameterName){ let parameterPromise; - let typesPanelValuesMap = {}; // Types have to be distinct for mapping to the conversion function's paramters + let typesPanelValuesMap = {}; // Types have to be distinct for mapping to the conversion function's parameters typesPanelValuesMap[sourceType]= sourceValue; let conversionFunctionId; @@ -602,7 +602,7 @@ class EducationPlatformApp { * @param {string[]} conversionFunctions list of conversion function ids to check * @param {boolean} convertMetamodel when true try to convert the metamodel using a remote tool service conversion function * available to the ToolsManager. - * @param {string} parameterName the name of the parameter to use when convering the metamodel. + * @param {string} parameterName the name of the parameter to use when converting the metamodel. * @param {string[]} typeValueMap the type values map the metamodel input value is added to if a conversion function is found * @returns {string} the id of a conversion function to use, null if none found. */ @@ -665,7 +665,7 @@ class EducationPlatformApp { * TODO: To be moved to the FunctionRegistry issue #40 * * @param {string} functionId the id of the action function - * @param {Object} typeValuesMap an object mapping action functions paramter types as keys to input values + * @param {Object} typeValuesMap an object mapping action functions parameter types as keys to input values * @param {string} parameterName name of the parameter * @returns Promise for the translated data * @@ -703,7 +703,7 @@ class EducationPlatformApp { * Requests the conversion function from the remote tool service * * @param {Object} parameters - * @param {ActionFunction} converstionFunction + * @param {ActionFunction} conversionFunction * @param {String} parameterName name of the parameter * @returns Promise for the translated data */ @@ -1021,7 +1021,7 @@ class EducationPlatformApp { /** * Poll for editor to become available. - * @param {String} statusUrl - the url for cheking the status of the editor panel. + * @param {String} statusUrl - the url for checking the status of the editor panel. * @param {String} editorInstanceUrl - the editor instance's url. * @param {String} editorPanelId - the id of the editor panel. * @param {String} editorActivityId - TODO remove as this can be found using editorPanelId to save having to specify in config. From 596578d866e74231bcb53e60287f728f157fb5ad Mon Sep 17 00:00:00 2001 From: Will Barnett Date: Thu, 21 Mar 2024 12:50:24 +0000 Subject: [PATCH 8/9] Removed duplicated tests following rebase. --- .../test/spec/testEducationPlatformAppSpec.js | 129 ------------------ 1 file changed, 129 deletions(-) diff --git a/platform/test/spec/testEducationPlatformAppSpec.js b/platform/test/spec/testEducationPlatformAppSpec.js index 59800d8..d51189e 100644 --- a/platform/test/spec/testEducationPlatformAppSpec.js +++ b/platform/test/spec/testEducationPlatformAppSpec.js @@ -725,135 +725,6 @@ describe("EducationPlatformApp", () => { }) }) - describe("selectConversionFunctionConvertMetamodel()", () => { - let platform; - - const SOURCE_TYPE = "test-source-type"; - const FILE_CONTENTS = "Test file contents."; - const MM_FILE_CONTENTS = "Test metamodel file contents." - const MM_TARGET_TYPE = "test-metamodel-target-type"; - const PARAM_NAME = "test"; - - const CONVERSION_FUNCTION_ID = "conversion-function-id"; - const X_FUNCTION_ID = "x-function-id"; // Not interested - - let toolsManagerSpy; - - beforeEach( () => { - // Setup - spyOn( EducationPlatformApp.prototype, "errorNotification"); - - platform = new EducationPlatformApp(); - - // platform - toolsManager - toolsManagerSpy = jasmine.createSpyObj(['getActionFunction', 'getConversionFunction']); - - toolsManagerSpy.getActionFunction.and.callFake( (functionId) => { - let actionFunctionConfig; - - switch (functionId){ - case CONVERSION_FUNCTION_ID: - actionFunctionConfig = { - parameters: [ - {name: "input", type: SOURCE_TYPE, instanceOf: "metamodel"}, - {name: "metamodel", type: MM_TARGET_TYPE} - ] - }; - break; - - case X_FUNCTION_ID: - actionFunctionConfig = { - parameters: [ - {name: "input", type: SOURCE_TYPE, instanceOf: "metamodel"}, - {name: "metamodel", type: "X"} - ] - } - break; - default: - actionFunctionConfig = null; - } - - return new ActionFunction(actionFunctionConfig) - }) - platform.toolsManager = toolsManagerSpy; - - }) - - it("returns a function id if a conversion is possible without considering the metamodel", async () => { - const CONSIDER_MM = false; - let mm_type = MM_TARGET_TYPE; - const typeValueMap = { [SOURCE_TYPE]: FILE_CONTENTS } - - // Call the target object - let selectConversionResult = await platform.selectConversionFunctionConvertMetamodel(mm_type, MM_FILE_CONTENTS, [CONVERSION_FUNCTION_ID, X_FUNCTION_ID], CONSIDER_MM, PARAM_NAME, typeValueMap) - - // Check the expected results - expect(selectConversionResult).toEqual(CONVERSION_FUNCTION_ID); - }) - - it("returns null if a conversion is not possible without considering the metamodel", async () => { - const CONSIDER_MM = false; - let mm_type = MM_TARGET_TYPE; - const typeValueMap = { [SOURCE_TYPE]: FILE_CONTENTS } - - // Call the target object - let selectConversionResult = await platform.selectConversionFunctionConvertMetamodel(mm_type, MM_FILE_CONTENTS, [X_FUNCTION_ID, X_FUNCTION_ID], CONSIDER_MM, PARAM_NAME, typeValueMap) - - // Check the expected results - expect(selectConversionResult).toEqual(null); - }) - - it("returns a function id, converts the metamodel, and adds the converted metamodel value to the typeValueMap if a conversion is possible considering the metamodel", async ()=>{ - const CONSIDER_MM = true; - let mm_type = "test-metamodel-type"; - const typeValueMap = { [SOURCE_TYPE]: FILE_CONTENTS } - - const MM_CONVERSION_FUNCTION_ID = "metamodel-conversion-function-id"; - const MM_CONVERTED_CONTENTS = "Test converted metamodel contents."; - - const callConversionReturn = new Promise(function(resolve) { - resolve({data: MM_CONVERTED_CONTENTS}); - }) - spyOn( EducationPlatformApp.prototype, "functionRegistry_callConversion").and.returnValue( - callConversionReturn); - - toolsManagerSpy.getConversionFunction.and.returnValues(null, MM_CONVERSION_FUNCTION_ID); // Find possible conversion on the second call - - // Call the target object - let selectConversionResult = await platform.selectConversionFunctionConvertMetamodel(mm_type, MM_FILE_CONTENTS, [CONVERSION_FUNCTION_ID, X_FUNCTION_ID], CONSIDER_MM, PARAM_NAME, typeValueMap) - - // Check the expected results - expect(platform.functionRegistry_callConversion).toHaveBeenCalledWith( - MM_CONVERSION_FUNCTION_ID, { [mm_type]: MM_FILE_CONTENTS}, PARAM_NAME - ); - - expect(typeValueMap[MM_TARGET_TYPE]).toEqual(MM_CONVERTED_CONTENTS); - - expect(selectConversionResult).toEqual(CONVERSION_FUNCTION_ID); - }) - - it("returns null if no conversion is available considering the metamodel", async () => { - const CONSIDER_MM = true; - let mm_type = "test-metamodel-type"; - const typeValueMap = { [SOURCE_TYPE]: FILE_CONTENTS } - - spyOn( EducationPlatformApp.prototype, "functionRegistry_callConversion"); - - toolsManagerSpy.getConversionFunction.and.returnValues(null, null); // Do not find possible conversion - - // Call the target object - let selectConversionResult = await platform.selectConversionFunctionConvertMetamodel(mm_type, MM_FILE_CONTENTS, [CONVERSION_FUNCTION_ID, X_FUNCTION_ID], CONSIDER_MM, PARAM_NAME, typeValueMap) - - // Check the expected results - expect(platform.functionRegistry_callConversion).not.toHaveBeenCalled(); - - expect(typeValueMap[MM_TARGET_TYPE]).toEqual(undefined); - - expect(selectConversionResult).toEqual(null); - }) - }) - - describe("notification()", () => { let platform; From e0089e6d962edece9aea5a65ad892f418255e6f6 Mon Sep 17 00:00:00 2001 From: Will Barnett Date: Thu, 21 Mar 2024 12:57:21 +0000 Subject: [PATCH 9/9] Corrected test name --- platform/test/spec/testEducationPlatformAppSpec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/test/spec/testEducationPlatformAppSpec.js b/platform/test/spec/testEducationPlatformAppSpec.js index d51189e..8a7922e 100644 --- a/platform/test/spec/testEducationPlatformAppSpec.js +++ b/platform/test/spec/testEducationPlatformAppSpec.js @@ -650,7 +650,7 @@ describe("EducationPlatformApp", () => { }) }) - describe("jsonRequestConversion()", () => { + describe("functionRegistry_callConversion()", () => { const TOOL_URL = "test://t1.url/toolfunction"; const CONVERSION_FUNCTION_ID = "test-function-id"; const PARAMETER_NAME = "testParameter1";