676 lines
24 KiB
TypeScript
676 lines
24 KiB
TypeScript
/*
|
|
* QQQ - Low-code Application Framework for Engineers.
|
|
* Copyright (C) 2021-2022. Kingsrook, LLC
|
|
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
|
|
* contact@kingsrook.com
|
|
* https://github.com/Kingsrook/
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* https://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
import axios from "axios";
|
|
import FormData = require("form-data");
|
|
import {QController} from "../../src/controllers/QController";
|
|
import {QException} from "../../src/exceptions/QException";
|
|
import {QAppMetaData} from "../../src/model/metaData/QAppMetaData";
|
|
import {QAppNodeType} from "../../src/model/metaData/QAppNodeType";
|
|
import {QAppTreeNode} from "../../src/model/metaData/QAppTreeNode";
|
|
import {QAuthenticationMetaData} from "../../src/model/metaData/QAuthenticationMetaData";
|
|
import {QBrandingMetaData} from "../../src/model/metaData/QBrandingMetaData";
|
|
import {QFieldMetaData} from "../../src/model/metaData/QFieldMetaData";
|
|
import {QFieldType} from "../../src/model/metaData/QFieldType";
|
|
import {QFrontendStepMetaData} from "../../src/model/metaData/QFrontendStepMetaData";
|
|
import {QInstance} from "../../src/model/metaData/QInstance";
|
|
import {QProcessMetaData} from "../../src/model/metaData/QProcessMetaData";
|
|
import {QTableMetaData} from "../../src/model/metaData/QTableMetaData";
|
|
import {QTableSection} from "../../src/model/metaData/QTableSection";
|
|
import {QJobComplete} from "../../src/model/processes/QJobComplete";
|
|
import {QJobError} from "../../src/model/processes/QJobError";
|
|
import {QJobRunning} from "../../src/model/processes/QJobRunning";
|
|
import {QJobStarted} from "../../src/model/processes/QJobStarted";
|
|
import {QPossibleValue} from "../../src/model/QPossibleValue";
|
|
import {QRecord} from "../../src/model/QRecord";
|
|
const fs = require("fs");
|
|
require("jest-localstorage-mock");
|
|
|
|
const baseURL = "http://localhost:8000";
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
// define if we're using mocks or not (in CI we always want to. but for local dev, //
|
|
// we may want to hit an actual backend server, e.g. at the baseURL given above) //
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
const useMock = true;
|
|
if (useMock)
|
|
{
|
|
jest.mock("axios");
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
// function to setup the axis mock, to return the contents of the specified file //
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
function mockGet(mockPath: string)
|
|
{
|
|
if (useMock)
|
|
{
|
|
axios.create = jest.fn(() => axios);
|
|
// @ts-ignore
|
|
axios.get = buildMockSuccessfulPromise(mockPath);
|
|
}
|
|
}
|
|
|
|
function mockGetError()
|
|
{
|
|
if (useMock)
|
|
{
|
|
axios.create = jest.fn(() => axios);
|
|
// @ts-ignore
|
|
axios.get = buildMockFailedPromise();
|
|
}
|
|
}
|
|
|
|
function mockPost(mockPath: string)
|
|
{
|
|
if (useMock)
|
|
{
|
|
axios.create = jest.fn(() => axios);
|
|
// @ts-ignore
|
|
axios.post = buildMockSuccessfulPromise(mockPath);
|
|
}
|
|
}
|
|
|
|
function mockPostError()
|
|
{
|
|
if (useMock)
|
|
{
|
|
axios.create = jest.fn(() => axios);
|
|
// @ts-ignore
|
|
axios.post = buildMockFailedPromise();
|
|
}
|
|
}
|
|
|
|
function mockPut(mockPath: string)
|
|
{
|
|
if (useMock)
|
|
{
|
|
axios.create = jest.fn(() => axios);
|
|
// @ts-ignore
|
|
axios.put = buildMockSuccessfulPromise(mockPath);
|
|
}
|
|
}
|
|
|
|
function mockPutError()
|
|
{
|
|
if (useMock)
|
|
{
|
|
axios.create = jest.fn(() => axios);
|
|
// @ts-ignore
|
|
axios.put = buildMockFailedPromise();
|
|
}
|
|
}
|
|
|
|
function mockDelete(mockPath: string)
|
|
{
|
|
if (useMock)
|
|
{
|
|
axios.create = jest.fn(() => axios);
|
|
// @ts-ignore
|
|
axios.delete = buildMockSuccessfulPromise(mockPath);
|
|
}
|
|
}
|
|
|
|
function mockDeleteError()
|
|
{
|
|
if (useMock)
|
|
{
|
|
axios.create = jest.fn(() => axios);
|
|
// @ts-ignore
|
|
axios.delete = buildMockFailedPromise();
|
|
}
|
|
}
|
|
|
|
function buildMockSuccessfulPromise(mockPath: string)
|
|
{
|
|
const json = fs.readFileSync(`./tests/mocks/${mockPath}`);
|
|
const response = {data: JSON.parse(json)};
|
|
return jest.fn(() =>
|
|
{
|
|
return new Promise(function (resolve)
|
|
{
|
|
// @ts-ignore
|
|
resolve(response);
|
|
});
|
|
});
|
|
}
|
|
|
|
function buildMockFailedPromise()
|
|
{
|
|
return jest.fn(() =>
|
|
{
|
|
return new Promise(function (_, reject)
|
|
{
|
|
reject(new Error());
|
|
});
|
|
});
|
|
}
|
|
|
|
describe("q controller test", () =>
|
|
{
|
|
beforeEach(() =>
|
|
{
|
|
QController.clearMemoization();
|
|
});
|
|
|
|
it("should load authentication meta data", async () =>
|
|
{
|
|
mockGet("metaData/authentication.json");
|
|
const qController = new QController(baseURL);
|
|
|
|
let authMetaData = await qController.getAuthenticationMetaData();
|
|
expect(authMetaData).toBeInstanceOf(QAuthenticationMetaData);
|
|
expect(authMetaData.type).toBe("MOCK");
|
|
expect(authMetaData.name).toBe("mock");
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// set the backend now to return the AUTH0 data, but, since it should be //
|
|
// cached in localstorage, make sure we still get back MOCK //
|
|
///////////////////////////////////////////////////////////////////////////
|
|
mockGet("metaData/authentication-auth0.json");
|
|
authMetaData = await qController.getAuthenticationMetaData();
|
|
expect(authMetaData.type).toBe("MOCK");
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// now clear the local storage, fetch again, and assert AUTH0 //
|
|
// note, we'll only do this if we're using mocks, where we can actually get an AUTH0 response from the mocked GET //
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
if (useMock)
|
|
{
|
|
qController.clearAuthenticationMetaDataLocalStorage();
|
|
authMetaData = await qController.getAuthenticationMetaData();
|
|
expect(authMetaData.type).toBe("AUTH_0");
|
|
}
|
|
});
|
|
|
|
it("should return meta data", async () =>
|
|
{
|
|
mockGet("metaData/index.json");
|
|
const qController = new QController(baseURL);
|
|
qController.setGotAuthentication();
|
|
|
|
const metaData = await qController.loadMetaData();
|
|
expect(metaData).toBeInstanceOf(QInstance);
|
|
|
|
const tables = metaData.tables;
|
|
expect(tables?.size).toBeGreaterThan(1);
|
|
const personTable = tables?.get("person");
|
|
expect(personTable).toBeInstanceOf(QTableMetaData);
|
|
expect(personTable?.label).toBe("Person");
|
|
const fields = personTable?.fields;
|
|
expect(fields).toBeUndefined(); // this meta data does not go down to the field level!
|
|
|
|
const processes = metaData.processes;
|
|
expect(processes?.size).toBeGreaterThan(0);
|
|
const greetProcess = processes?.get("greet");
|
|
expect(greetProcess).toBeInstanceOf(QProcessMetaData);
|
|
expect(greetProcess?.label).toBe("Greet People");
|
|
|
|
const apps = metaData.apps;
|
|
expect(apps?.size).toBeGreaterThan(0);
|
|
const greetingsApp = apps?.get("greetingsApp");
|
|
expect(greetingsApp).toBeInstanceOf(QAppMetaData);
|
|
expect(greetingsApp?.label).toBe("Greetings App");
|
|
const greetPeopleProcess = greetingsApp?.children?.[0];
|
|
expect(greetPeopleProcess).toBeInstanceOf(QAppTreeNode);
|
|
expect(greetPeopleProcess?.label).toBe("Greet People");
|
|
expect(greetPeopleProcess?.type).toBe(QAppNodeType.PROCESS);
|
|
const peopleApp = apps?.get("peopleApp");
|
|
const greetingsAppUnderPeople = peopleApp?.children?.find(child => child.name === "greetingsApp");
|
|
expect(greetingsAppUnderPeople).toBeInstanceOf(QAppTreeNode);
|
|
expect(greetingsAppUnderPeople?.children).toBeUndefined(); // apps map is Not nested
|
|
|
|
const appTree = metaData.appTree;
|
|
expect(appTree?.length).toBeGreaterThan(0);
|
|
const peopleAppUnderTree = appTree?.find(app => app.name === "peopleApp");
|
|
expect(peopleAppUnderTree).toBeInstanceOf(QAppTreeNode);
|
|
const greetingsAppUnderPeopleInTree = peopleAppUnderTree?.children?.find(child => child.name === "greetingsApp");
|
|
expect(greetingsAppUnderPeopleInTree).toBeInstanceOf(QAppTreeNode);
|
|
expect(greetingsAppUnderPeopleInTree?.children?.length).toBeGreaterThan(0); // apps tree IS nested
|
|
|
|
const branding = metaData.branding;
|
|
expect(branding).toBeInstanceOf(QBrandingMetaData);
|
|
expect(branding?.companyName).toBe("Kingsrook");
|
|
expect(branding?.icon).toBe("kr-icon.png");
|
|
expect(branding?.logo).toBe("kr-logo.png");
|
|
});
|
|
|
|
it("should return an error with a bad base url meta data", async () =>
|
|
{
|
|
try
|
|
{
|
|
mockGetError();
|
|
const qController = new QController("http://notahost:123");
|
|
qController.setGotAuthentication();
|
|
const metaData = await qController.loadMetaData();
|
|
expect(metaData).toBeNull();
|
|
}
|
|
catch (error)
|
|
{
|
|
expect(error).toBeInstanceOf(QException);
|
|
}
|
|
});
|
|
|
|
it("should return table meta data", async () =>
|
|
{
|
|
mockGet("metaData/table/carrier.json");
|
|
const qController = new QController(baseURL);
|
|
qController.setGotAuthentication();
|
|
|
|
const tableMetaData = await qController.loadTableMetaData("carrier");
|
|
expect(tableMetaData).toBeInstanceOf(QTableMetaData);
|
|
expect(tableMetaData.fields).toBeInstanceOf(Map);
|
|
expect(tableMetaData?.label).toBe("Carrier");
|
|
|
|
const nameField = tableMetaData?.fields?.get("name");
|
|
expect(nameField).toBeInstanceOf(QFieldMetaData);
|
|
expect(nameField?.name).toBe("name");
|
|
expect(nameField?.label).toBe("Name");
|
|
expect(nameField?.type).toBe(QFieldType.STRING);
|
|
|
|
const sections = tableMetaData?.sections;
|
|
expect(sections).toBeDefined();
|
|
expect(sections?.length).toBeGreaterThan(0);
|
|
const section = sections?.[0];
|
|
expect(section).toBeInstanceOf(QTableSection);
|
|
expect(section?.name).toBeDefined();
|
|
expect(section?.iconName).toBeDefined();
|
|
expect(section?.fieldNames).toBeDefined();
|
|
expect(section?.fieldNames?.length).toBeGreaterThan(0);
|
|
|
|
//////////////////////////////////////////////////////////
|
|
// make sure it can be fetched again (from memoization) //
|
|
//////////////////////////////////////////////////////////
|
|
const tableMetaData2 = await qController.loadTableMetaData("carrier");
|
|
expect(tableMetaData2).toBeInstanceOf(QTableMetaData);
|
|
expect(tableMetaData2.fields).toBeInstanceOf(Map);
|
|
expect(tableMetaData2?.label).toBe("Carrier");
|
|
});
|
|
|
|
it("should fail table meta data for bad table name", async () =>
|
|
{
|
|
try
|
|
{
|
|
mockGetError();
|
|
const qController = new QController(baseURL);
|
|
qController.setGotAuthentication();
|
|
|
|
const tableMetaData = await qController.loadTableMetaData("currier");
|
|
expect(tableMetaData).toBeNull();
|
|
}
|
|
catch (error)
|
|
{
|
|
expect(error).toBeInstanceOf(QException);
|
|
}
|
|
});
|
|
|
|
it("should return process meta data", async () =>
|
|
{
|
|
mockGet("metaData/process/greetInteractive.json");
|
|
const qController = new QController(baseURL);
|
|
qController.setGotAuthentication();
|
|
|
|
const processMetaData = await qController.loadProcessMetaData(
|
|
"greetInteractive"
|
|
);
|
|
expect(processMetaData).toBeInstanceOf(QProcessMetaData);
|
|
expect(processMetaData?.label).toBe("Greet Interactive");
|
|
expect(processMetaData?.frontendSteps).toBeInstanceOf(Array);
|
|
|
|
const setupStep = processMetaData?.frontendSteps?.[0];
|
|
expect(setupStep).toBeInstanceOf(QFrontendStepMetaData);
|
|
expect(setupStep?.name).toBe("setup");
|
|
expect(setupStep?.label).toBe("Setup");
|
|
expect(setupStep?.formFields).toBeInstanceOf(Array);
|
|
expect(setupStep?.formFields?.[0]).toBeInstanceOf(QFieldMetaData);
|
|
expect(setupStep?.formFields?.[0].name).toBe("greetingPrefix");
|
|
});
|
|
|
|
it("should fail process meta data for bad process name", async () =>
|
|
{
|
|
try
|
|
{
|
|
mockGetError();
|
|
const qController = new QController(baseURL);
|
|
const processMetaData = await qController.loadProcessMetaData("gort");
|
|
qController.setGotAuthentication();
|
|
|
|
expect(processMetaData).toBeNull();
|
|
}
|
|
catch (error)
|
|
{
|
|
expect(error).toBeInstanceOf(QException);
|
|
}
|
|
});
|
|
|
|
it("should create a record", async () =>
|
|
{
|
|
let data = {
|
|
firstName: "John",
|
|
lastName: "Doe",
|
|
email: "jdoe@kingsrook.com",
|
|
};
|
|
mockPost("data/person/post.json");
|
|
const qController = new QController(baseURL);
|
|
const personRecord: QRecord = await qController.create("person", data);
|
|
expect(personRecord).toBeInstanceOf(QRecord);
|
|
expect(personRecord.values.get("firstName")).toBe("John");
|
|
});
|
|
|
|
it("should update a record", async () =>
|
|
{
|
|
let data = {
|
|
firstName: "John",
|
|
lastName: "Doe",
|
|
email: "jdoe@kingsrook.com",
|
|
};
|
|
mockPut("data/person/put.json");
|
|
const qController = new QController(baseURL);
|
|
const personRecord: QRecord = await qController.update("person", 1, data);
|
|
expect(personRecord).toBeInstanceOf(QRecord);
|
|
expect(personRecord.values.get("firstName")).toBe("John");
|
|
});
|
|
|
|
it("should query for records", async () =>
|
|
{
|
|
mockPost("data/person/query.json");
|
|
const qController = new QController(baseURL);
|
|
const personRecords: QRecord[] = await qController.query("person");
|
|
expect(personRecords).toBeInstanceOf(Array);
|
|
expect(personRecords.length).toBe(6);
|
|
});
|
|
|
|
it("should query for a limited number of records", async () =>
|
|
{
|
|
mockPost("data/person/queryLimit=2.json");
|
|
const qController = new QController(baseURL);
|
|
const personRecords: QRecord[] = await qController.query("person", undefined);
|
|
expect(personRecords).toBeInstanceOf(Array);
|
|
expect(personRecords.length).toBe(2);
|
|
});
|
|
|
|
it("should get a single record by id", async () =>
|
|
{
|
|
mockGet("data/person/get5.json");
|
|
const qController = new QController(baseURL);
|
|
const personRecord: QRecord = await qController.get("person", 5);
|
|
expect(personRecord).toBeInstanceOf(QRecord);
|
|
expect(personRecord.values).toBeInstanceOf(Map);
|
|
expect(personRecord.values.get("firstName")).toBeDefined();
|
|
});
|
|
|
|
it("should delete a record", async () =>
|
|
{
|
|
mockDelete("data/person/delete6.json");
|
|
const qController = new QController(baseURL);
|
|
const numberDeleted: number = await qController.delete("person", 6);
|
|
expect(numberDeleted).toBe(1);
|
|
});
|
|
|
|
it("should throw when a delete fails", async () =>
|
|
{
|
|
try
|
|
{
|
|
mockDelete("data/person/delete-1.json");
|
|
const qController = new QController(baseURL);
|
|
const numberDeleted: number = await qController.delete("person", -1);
|
|
expect(numberDeleted).toBeNull();
|
|
}
|
|
catch (error)
|
|
{
|
|
expect(error).toBeInstanceOf(QException);
|
|
}
|
|
});
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// function that non-mock mode can use, to actually wait on server to finish running async processes //
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
const sleep = (delay: number) =>
|
|
{
|
|
if (useMock)
|
|
{
|
|
return new Promise((resolve) => setTimeout(resolve, 0));
|
|
}
|
|
else
|
|
{
|
|
return new Promise((resolve) => setTimeout(resolve, delay));
|
|
}
|
|
};
|
|
|
|
it("should init a process that goes async", async () =>
|
|
{
|
|
let processName = "simpleSleep";
|
|
mockPost("processes/simpleSleep/initStarted.json");
|
|
const qController = new QController(baseURL);
|
|
const initResponse = await qController.processInit(
|
|
processName,
|
|
"_qStepTimeoutMillis=10&sleepMillis=100"
|
|
);
|
|
expect(initResponse).toBeInstanceOf(QJobStarted);
|
|
const qJobStarted = initResponse as QJobStarted;
|
|
|
|
mockGet("processes/simpleSleep/statusRunning.json");
|
|
const statusResponse1 = await qController.processJobStatus(
|
|
processName,
|
|
qJobStarted.processUUID,
|
|
qJobStarted.jobUUID
|
|
);
|
|
expect(statusResponse1).toBeInstanceOf(QJobRunning);
|
|
|
|
/////////////////////////////////////////
|
|
// wait for the job to actually finish //
|
|
/////////////////////////////////////////
|
|
await sleep(750);
|
|
|
|
mockGet("processes/simpleSleep/statusComplete.json");
|
|
const statusResponse2 = await qController.processJobStatus(
|
|
processName,
|
|
qJobStarted.processUUID,
|
|
qJobStarted.jobUUID
|
|
);
|
|
expect(statusResponse2).toBeInstanceOf(QJobComplete);
|
|
});
|
|
|
|
it("should init a process that completes synchronously", async () =>
|
|
{
|
|
let processName = "simpleSleep";
|
|
mockGet("metaData/table/carrier.json");
|
|
mockPost("processes/simpleSleep/initComplete.json");
|
|
const qController = new QController(baseURL);
|
|
const initResponse = await qController.processInit(
|
|
processName,
|
|
"_qStepTimeoutMillis=100&sleepMillis=10"
|
|
);
|
|
expect(initResponse).toBeInstanceOf(QJobComplete);
|
|
});
|
|
|
|
it("should run a step in a process that goes async", async () =>
|
|
{
|
|
let processName = "sleepInteractive";
|
|
mockPost("processes/sleepInteractive/initComplete.json");
|
|
const qController = new QController(baseURL);
|
|
const initResponse = await qController.processInit(processName);
|
|
expect(initResponse).toBeInstanceOf(QJobComplete);
|
|
const qJobComplete = initResponse as QJobComplete;
|
|
|
|
mockPost("processes/sleepInteractive/stepStarted.json");
|
|
const stepResponse = await qController.processStep(
|
|
processName,
|
|
qJobComplete.processUUID,
|
|
qJobComplete.nextStep,
|
|
"_qStepTimeoutMillis=10&sleepMillis=100"
|
|
);
|
|
expect(stepResponse).toBeInstanceOf(QJobStarted);
|
|
const qJobStarted = stepResponse as QJobStarted;
|
|
|
|
/////////////////////////////////////////
|
|
// wait for the job to actually finish //
|
|
/////////////////////////////////////////
|
|
await sleep(200);
|
|
mockGet("processes/simpleSleep/statusComplete.json");
|
|
const statusResponse = await qController.processJobStatus(
|
|
processName,
|
|
qJobComplete.processUUID,
|
|
qJobStarted.jobUUID
|
|
);
|
|
expect(statusResponse).toBeInstanceOf(QJobComplete);
|
|
});
|
|
|
|
it("should run a step in a process that does NOT go async with a query string", async () =>
|
|
{
|
|
let processName = "sleepInteractive";
|
|
mockPost("processes/sleepInteractive/initComplete.json");
|
|
const qController = new QController(baseURL);
|
|
const initResponse = await qController.processInit(processName);
|
|
expect(initResponse).toBeInstanceOf(QJobComplete);
|
|
const qJobComplete = initResponse as QJobComplete;
|
|
|
|
mockPost("processes/sleepInteractive/stepComplete.json");
|
|
const stepResponse = await qController.processStep(
|
|
processName,
|
|
qJobComplete.processUUID,
|
|
qJobComplete.nextStep,
|
|
"_qStepTimeoutMillis=100&sleepMillis=10"
|
|
);
|
|
expect(stepResponse).toBeInstanceOf(QJobComplete);
|
|
const qJobComplete2 = stepResponse as QJobComplete;
|
|
|
|
///////////////////////////////////////////////////
|
|
// assert that we got back a different next-step //
|
|
///////////////////////////////////////////////////
|
|
expect(qJobComplete.nextStep).not.toBe(qJobComplete2.nextStep);
|
|
});
|
|
|
|
it("should run a step in a process that does NOT go async with a POST body", async () =>
|
|
{
|
|
let processName = "sleepInteractive";
|
|
mockPost("processes/sleepInteractive/initComplete.json");
|
|
const qController = new QController(baseURL);
|
|
const initResponse = await qController.processInit(processName);
|
|
expect(initResponse).toBeInstanceOf(QJobComplete);
|
|
const qJobComplete = initResponse as QJobComplete;
|
|
|
|
const formData = new FormData();
|
|
formData.append("sleepMillis", 10);
|
|
formData.append("_qStepTimeoutMillis", 100);
|
|
|
|
mockPost("processes/sleepInteractive/stepComplete.json");
|
|
const stepResponse = await qController.processStep(
|
|
processName,
|
|
qJobComplete.processUUID,
|
|
qJobComplete.nextStep,
|
|
formData
|
|
);
|
|
expect(stepResponse).toBeInstanceOf(QJobComplete);
|
|
const qJobComplete2 = stepResponse as QJobComplete;
|
|
|
|
///////////////////////////////////////////////////
|
|
// assert that we got back a different next-step //
|
|
///////////////////////////////////////////////////
|
|
expect(qJobComplete.nextStep).not.toBe(qJobComplete2.nextStep);
|
|
});
|
|
|
|
it("should handle an exception from an init", async () =>
|
|
{
|
|
let processName = "simpleThrow";
|
|
mockPost("processes/simpleThrow/initError.json");
|
|
const qController = new QController(baseURL);
|
|
const initResponse = await qController.processInit(
|
|
processName,
|
|
"_qStepTimeoutMillis=100&sleepMillis=10"
|
|
);
|
|
expect(initResponse).toBeInstanceOf(QJobError);
|
|
});
|
|
|
|
it("should handle an exception from an async init", async () =>
|
|
{
|
|
let processName = "simpleThrow";
|
|
mockPost("processes/simpleThrow/initStarted.json");
|
|
const qController = new QController(baseURL);
|
|
const initResponse = await qController.processInit(
|
|
processName,
|
|
"_qStepTimeoutMillis=10&sleepMillis=100"
|
|
);
|
|
expect(initResponse).toBeInstanceOf(QJobStarted);
|
|
const qJobStarted = initResponse as QJobStarted;
|
|
|
|
await sleep(200);
|
|
mockGet("processes/simpleThrow/statusError.json");
|
|
const statusResponse = await qController.processJobStatus(
|
|
processName,
|
|
qJobStarted.processUUID,
|
|
qJobStarted.jobUUID
|
|
);
|
|
expect(statusResponse).toBeInstanceOf(QJobError);
|
|
});
|
|
|
|
it("should return process records", async () =>
|
|
{
|
|
let processName = "greet";
|
|
mockPost("processes/greet/initComplete.json");
|
|
const qController = new QController(baseURL);
|
|
const initResponse = await qController.processInit(
|
|
processName,
|
|
"recordsParam=recordIds&recordIds=2,3"
|
|
);
|
|
expect(initResponse).toBeInstanceOf(QJobComplete);
|
|
const qJobComplete = initResponse as QJobComplete;
|
|
const processUUID = qJobComplete.processUUID;
|
|
|
|
mockGet("processes/greet/records.json");
|
|
const response = await qController.processRecords(
|
|
processName,
|
|
processUUID,
|
|
0,
|
|
20
|
|
);
|
|
const records = response.records;
|
|
expect(records).toBeInstanceOf(Array);
|
|
expect(records.length).toBe(2);
|
|
expect(records[0].values).toBeInstanceOf(Map);
|
|
expect(records[0].values.get("id")).not.toBeNull();
|
|
expect(records[0].values.get("firstName")).not.toBeNull();
|
|
expect(response.totalRecords).toBe(2);
|
|
});
|
|
|
|
it("should get data for a widget", async () =>
|
|
{
|
|
mockGet("widget/PersonsByCreateDateBarChart.json");
|
|
const qController = new QController(baseURL);
|
|
const widget = await qController.widget("PersonsByCreateDateBarChart");
|
|
console.log(widget);
|
|
expect(widget).not.toBeNull();
|
|
});
|
|
|
|
it("should get options for a possible value", async () =>
|
|
{
|
|
mockPost("data/person/possibleValues-homeStateId.json");
|
|
const qController = new QController(baseURL);
|
|
const result = await qController.possibleValues("person", null, "homeStateId", "");
|
|
expect(result).not.toBeNull();
|
|
expect(result).toBeInstanceOf(Array);
|
|
expect(result.length).toBe(2);
|
|
expect(result[0]).toBeInstanceOf(QPossibleValue);
|
|
expect(result[0].id).toBe(1);
|
|
expect(result[0].label).toBe("IL");
|
|
});
|
|
|
|
});
|