trident-beta
Version:
trident is a sample and lightly tools aims to improve collaboration efficiency between SDET and QA based on initiative from Einstein/TestIT.
1,797 lines • 58.3 kB
text/typescript
/**
* TestIt API
*/
import {
CaseInfo,
IBuild,
IGetSuggestTestCasesResponseDTO,
IProject,
IProjectInfo,
IProjectKeyword,
ISectionInfo,
ISuite,
ITestCase,
ITestExecution,
ITestPlan,
IVersion,
stepsInfo
} from "./dto";
import { IGlobalData } from "./dto";
import _, { identity } from "lodash";
import qs, { stringify } from "qs";
import * as Parser from "../parser/parser";
import HttpClient from "../util/httpClient";
import {
PREDEFINED_PROPERTY_MAP,
PREDEFINED_VALUE_MAP,
OPERATOR_MAP,
Scope,
CacheKey,
KeywordsMap
} from "./constants";
import { SearchOptions, TemplateInfo } from "./dto";
import { PASSWORD, USERNAME } from "../fixtures/fixtures";
const log4js = require("log4js");
const logger = log4js.getLogger();
export default class TestItSDK {
private endpoint: string;
private userName: string | null;
private accessToken: string | null;
private cache: Map<string, any>;
private httpClient: HttpClient;
constructor(endpoint: string) {
this.endpoint = endpoint;
this.userName = null;
this.accessToken = null;
this.cache = new Map<string, any>();
this.httpClient = new HttpClient();
}
/**
* Return true if client is authorized.
*/
public getAutorized(): boolean {
return this.accessToken != null;
}
/**
* Login to TestIt. Save cookies if login successfully.
* @param username
* @param password
*/
public async login(
username: string | undefined,
password: string | undefined
): Promise<void> {
try {
const url = `${this.endpoint}/api/v1/login`;
const data = { username, password };
const headers = {
"Content-Type": "application/json"
};
const config = { headers, data };
const response = await this.httpClient.post(url, config);
this.userName = response.data.username;
this.accessToken = response.data.access_token;
logger.debug(response.data);
await this.init();
} catch (err) {
throw new Error(
"Failed to login TestIt, please check your username and password."
);
}
logger.debug("----Welcome! Login Successfully!-----");
}
/**
* Logout Testit, delete cookies.
*/
public logout(): void {
this.userName = null;
this.accessToken = null;
}
/**
* Initialize sdk,fetch global data.
* @return {Promise<void>}
*/
public async init(): Promise<void> {
const globalData = await this.getGlobalData();
this.cache.set(CacheKey.GLOBAL_DATA, globalData);
}
/**
* Fetch fields information by project id for further using.
* @param projectId
*/
public async fetchFieldsInfoById(projectId: number): Promise<any> {
const url = `${this.endpoint}/api/v1/fields?projectId=${projectId}`;
const headers = {
Authorization: this.accessToken,
"Content-type": "application/json"
};
const config = {
headers
};
const response = await this.httpClient.get(url, config);
return response.data;
}
/**
* Get search elements map from fields by name.
* @param response
* @param name (like Keywords Subtype...)
*/
private async getFieldsInfoMapByName(
response: any,
name: string
): Promise<Map<string, number>> {
var fieldsIdxMap = await this.getFieldsIndexMap(response);
var index = fieldsIdxMap.get(name);
if (index == undefined) {
throw new Error(`Not found the name : ${name}`);
}
const values = response[index].values;
var resMap = new Map<string, number>();
for (var i = 0; i < values.length; i++) {
resMap.set(values[i].name, values[i].id);
}
return resMap;
}
/**
* Get field's response values map (name -> index).
* @param response
*/
private async getFieldsIndexMap(response: any): Promise<Map<string, number>> {
var valuesMap = new Map<string, number>();
for (var i = 0; i < response.length; i++) {
valuesMap.set(response[i].name, i);
}
return valuesMap;
}
/**
* Get field's response values map (name -> id).
* @param response
*/
private async getFieldsIdMap(response: any): Promise<Map<string, number>> {
var valuesMap = new Map<string, number>();
for (var i = 0; i < response.length; i++) {
valuesMap.set(response[i].name, response[i].id);
}
return valuesMap;
}
/**
* Get projects.
* @return {Promise<IProject[]>}
*/
public async getProjects(): Promise<IProject[]> {
const cacheKey = CacheKey.PROJECTS;
if (this.cache.has(cacheKey)) {
return this.cache.get(cacheKey);
}
const url = `${this.endpoint}/api/v1/projects`;
const headers = {
Authorization: this.accessToken,
"Content-Type": "application/json"
};
const config = { headers };
const response = await this.httpClient.get(url, config);
this.cache.set(cacheKey, response.data);
return response.data;
}
/**
* Generate prefix project map.
*/
private async genPrefixProjectMap(): Promise<Map<number, string>> {
const response = await this.getProjects();
var prefixMap = new Map<number, string>();
for (var i = 0; i < response.length; i++) {
prefixMap.set(response[i].id, response[i].prefix);
}
return prefixMap;
}
/**
* Get project by name.
* @param projectName
*/
public async getProjectByName(
projectName: string
): Promise<IProject | undefined> {
const totalProjects = await this.getProjects();
return _.find(totalProjects, p => p.name === projectName);
}
/**
* Get project id by name.
* @param projectName
*/
private async getProjectIdByName(projectName: string): Promise<any> {
const project = await this.getProjectByName(projectName);
if (!project) {
throw new Error(`Project not found : ${projectName}.`);
}
return project["id"];
}
/**
* Get project by project id.
* @param projectId
*/
public async getProjectById(projectId: number): Promise<IProjectInfo> {
const cacheKey = `${CacheKey.PROJECT} : ${projectId}`;
if (this.cache.has(cacheKey)) {
return this.cache.get(cacheKey);
}
const url = `${this.endpoint}/api/v1/project/${projectId}`;
const headers = {
Authorization: this.accessToken,
"Content-Type": "application/json"
};
const config = { headers };
const response = await this.httpClient.get(url, config);
//update : response total data of project.
this.cache.set(cacheKey, response.data);
return response.data;
}
/**
* Get keywords by project id.
* 【Error】Project doesn't include keywords!Not really go.
* @param projectId
*/
public async getKeywordsByProjectId(
projectId: number
): Promise<IProjectKeyword[]> {
const cacheKey = `${CacheKey.KEYWORDS} : ${projectId}`;
if (this.cache.has(cacheKey)) {
return this.cache.get(cacheKey);
}
const url = `${this.endpoint}/api/v1/project/${projectId}`;
const headers = {
Authorization: this.accessToken,
"Content-Type": "application/json"
};
const config = { headers };
const response = await this.httpClient.get(url, config);
this.cache.set(cacheKey, response.data);
return response.data;
}
/**
* Get project tree by project id.
* @param projectId
*/
public async getProjectTreeById(projectId: number): Promise<ISuite[]> {
const cacheKey = `${CacheKey.PROJECT_TREE} : ${projectId}`;
if (this.cache.has(cacheKey)) {
return this.cache.get(cacheKey);
}
const url = `${this.endpoint}/api/v1/project/${projectId}/tree`;
const headers = {
Authorization: this.accessToken,
"Content-Type": "application/json"
};
const config = { headers };
const response = await this.httpClient.get(url, config);
this.cache.set(cacheKey, response.data);
return response.data;
}
/**
* Get section by section id.
* @param sectionId
*/
public async getSectionById(sectionId: number): Promise<ISectionInfo> {
const cacheKey = `${CacheKey.SECTION} : ${sectionId}`;
if (this.cache.has(cacheKey)) {
return this.cache.get(cacheKey);
}
const url = `${this.endpoint}/api/v1/section/${sectionId}`;
const headers = {
Authorization: this.accessToken,
"Content-Type": "application/json"
};
const config = { headers };
const response = await this.httpClient.get(url, config);
this.cache.set(cacheKey, response.data);
return response.data;
}
/**
* Get test case by test case id. - 17
* @param testCaseId
*/
public async getTestCaseById(testCaseId: number): Promise<ITestCase> {
try {
const url = `${this.endpoint}/api/v1/case/${testCaseId}`;
const headers = {
Authorization: this.accessToken,
"Content-Type": "application/json"
};
const config = { headers };
const response = await this.httpClient.get(url, config);
return response.data;
} catch (err) {
throw new Error("404 Not Found.Please make sure the right testCaseId");
}
}
/**
* Get many test cases by test case ids.
* @param testCaseIds
*/
public async getTestCasesByIds(testCaseIds: number[]): Promise<ITestCase[]> {
var prefix = `${this.endpoint}/api/v1/cases?`;
testCaseIds.forEach(function (value) {
prefix = `${prefix}id=${value}&`;
});
const url = prefix.substring(0, prefix.length - 1);
const headers = {
Authorization: this.accessToken,
"Content-Type": "application/json"
};
const config = { headers };
const response = await this.httpClient.get(url, config);
return response.data;
}
/**
* Get test plans from test case by test case id.
* @param testCaseId
*/
public async getTestPlansByTestCaseId(
testCaseId: number
): Promise<ITestPlan[]> {
const cacheKey = `${CacheKey.TEST_PLAN} : ${testCaseId}`;
if (this.cache.has(cacheKey)) {
return this.cache.get(cacheKey);
}
const url = `${this.endpoint}/api/v1/case/${testCaseId}/testplans`;
const headers = {
Authorization: this.accessToken,
"Content-Type": "application/json"
};
const config = { headers };
const response = await this.httpClient.get(url, config);
this.cache.set(cacheKey, response.data);
return response.data;
}
/**
* Get test plans by project ids.
* @param projectIds
*/
public async getTestPlansByProjectIds(
projectIds: number[]
): Promise<ITestPlan[]> {
var prefix = `${this.endpoint}/api/v1/testplans?`;
projectIds.forEach(function (value) {
prefix = `${prefix}projectId=${value}&`;
});
const url = prefix.substring(0, prefix.length - 1);
const headers = {
Authorization: this.accessToken,
"Content-Type": "application/json"
};
const config = { headers };
const response = await this.httpClient.get(url, config);
return response.data;
}
/**
* Get execution-history by test case id.
* @param testCaseId
*/
public async getExecutionHistoryByTestCaseId(
testCaseId: number
): Promise<ITestExecution> {
const url = `${this.endpoint}/api/v1/case/${testCaseId}/execution-history`;
const headers = {
Authorization: this.accessToken,
"Content-Type": "application/json"
};
const config = { headers };
const response = await this.httpClient.get(url, config);
return response.data;
}
/**
* Get test case version by version id.
* @param versionId
*/
public async getCaseVersionByVersionId(versionId: number): Promise<IVersion> {
const url = `${this.endpoint}/api/v1/case/version/${versionId}`;
const headers = {
Authorization: this.accessToken,
"Content-Type": "application/json"
};
const config = { headers };
const response = await this.httpClient.get(url, config);
return response.data;
}
/**
* Get test case by key.
* 【Example】key = JPT-3166
* @param key
*/
public async getTestCaseByKey(key: string): Promise<ITestCase> {
const url = `${this.endpoint}/api/v1/case/${key}`;
const headers = {
Authorization: this.accessToken,
"Content-Type": "applicaiton/json"
};
const config = { headers };
const response = await this.httpClient.get(url, config);
return response.data;
}
/**
* Get builds by test plan id.
* @param testPlanId
*/
public async getBuildsByTestPlanId(testPlanId: number): Promise<IBuild[]> {
const url = `${this.endpoint}/api/v1/testplan/${testPlanId}/builds`;
const headers = {
Authorization: this.accessToken,
"Content-Type": "application/json"
};
const config = { headers };
const response = await this.httpClient.get(url, config);
return response.data;
}
/**
* Get test plan by test plan id.
* @param testPlanId
*/
public async getTestPlanById(testPlanId: number): Promise<ITestPlan> {
const url = `${this.endpoint}/api/v1/testplan/${testPlanId}`;
const headers = {
Authorization: this.accessToken,
"Content-Type": "application/json"
};
const config = { headers };
const response = await this.httpClient.get(url, config);
return response.data;
}
/**
* Get tree by test plan id.
* @param testPlanId
*/
public async getTreeByTestPlanId(testPlanId: number): Promise<ITestPlan> {
const url = `${this.endpoint}/api/v1/testplan/${testPlanId}/tree`;
const headers = {
Authorization: this.accessToken,
"Content-Type": "application/json"
};
const config = { headers };
const response = await this.httpClient.get(url, config);
return response.data;
}
/**
* Get execution progress by test plan id.
* @param testPlanId
*/
public async getExecutionProgressByTestPlanId(
testPlanId: number
): Promise<ITestExecution> {
const url = `${this.endpoint}/api/v1/testplan/${testPlanId}/execution-progress`;
const headers = {
Authorization: this.accessToken,
"Content-Type": "application/json"
};
const config = { headers };
const response = await this.httpClient.get(url, config);
return response.data;
}
/**
* Get build by build id.
* @param buildId
*/
public async getBuildById(buildId: number): Promise<IBuild> {
const url = `${this.endpoint}/api/v1/build/${buildId}`;
const headers = {
Authorization: this.accessToken,
"Content-Type": "application/json"
};
const config = { headers };
const response = await this.httpClient.get(url, config);
return response.data;
}
/**
* Get suite by suite id.
* @param suiteId
*/
public async getSuiteById(suiteId: number): Promise<ISuite> {
const cacheKey = `${CacheKey.SUITES}:${suiteId}`;
if (this.cache.has(cacheKey)) {
return this.cache.get(cacheKey);
}
const url = `${this.endpoint}/api/v1/suite/${suiteId}`;
const headers = {
Authorization: this.accessToken,
"Content-Type": "application/json"
};
const config = { headers };
const response = await this.httpClient.get(url, config);
this.cache.set(cacheKey, response.data);
return response.data;
}
/**
* Get suite tree by suite id.
* @param suiteId
*/
public async getSuiteTreeById(suiteId: number): Promise<ISuite[]> {
const cacheKey = `${CacheKey.SUITE_TREE}:${suiteId}`;
if (this.cache.has(cacheKey)) {
return this.cache.get(cacheKey);
}
const url = `${this.endpoint}/api/v1/suite/${suiteId}/tree`;
const headers = {
Authorization: this.accessToken,
"Content-Type": "application/json"
};
const config = { headers };
const response = await this.httpClient.get(url, config);
this.cache.set(cacheKey, response.data);
return response.data;
}
/* Search API use in cases */
/**
* Search test cases by json query.
* @param query
* @param scope
*/
private async searchTestCasesByJsonQuery(
query: any,
scope: Scope = "TEST_SUITES"
): Promise<any> {
const criterionJson = query; /* JSON.stringify(query); */
const url = `${this.endpoint}/testCases/search`;
const data = {
type: "search",
scope,
criterionJson
};
const headers = {
Authorization: this.accessToken,
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"
};
const config = {
headers,
data: qs.stringify(data)
};
const response = await this.httpClient.post(url, config);
return response.data;
}
/**
* Flatten response data.
* @param root
*/
private flat(root: any) {
const cases: any[] = [];
const fifo: any[] = [root];
while (fifo.length > 0) {
const node = fifo.shift();
if ("case" !== node.type) {
if (node.children && node.children.length > 0) {
node.children.forEach((child: { path: any[] }) => {
if (!child.path) {
child.path = [];
}
child.path.push(node.name);
});
fifo.push(...node.children);
}
} else {
cases.push(node);
}
}
return cases;
}
/**
* Search and generate template info by search Option.
* @param searchOption
*/
public async generateTemplateInfoByOptions(
searchOption: SearchOptions
): Promise<any> {
const query = await this.generateQuery(searchOption);
const response = await this.searchTestCasesByQuery(
query,
"TEST_SUITES",
searchOption.suiteName
);
const flatResponse = this.flat(response);
const flatLength = flatResponse.length;
const resultData = [];
for (var i = 0; i < flatLength; i++) {
var tempKey = `${flatResponse[i].prefix}-${flatResponse[i].externalId}`;
resultData.push(await this.generateTemplatesInfoByKey(tempKey));
}
return resultData;
}
/**
* Store template file by search options.
* @param searchOption
* @param path
*/
public async storeTemplateFileByOptions(
searchOption: SearchOptions,
path: string
): Promise<any> {
const query = await this.generateQuery(searchOption);
const response = await this.searchTestCasesByQuery(
query,
"TEST_SUITES",
searchOption.suiteName
);
const flatResponse = this.flat(response);
const flatLength = flatResponse.length;
for (var i = 0; i < flatLength; i++) {
var tempKey = `${flatResponse[i].prefix}-${flatResponse[i].externalId}`;
var fileName = `${path}${tempKey}.test.ts`;
var info = await this.generateTemplatesInfoByKey(tempKey);
this.writeTemplateInfo(info, fileName);
}
logger.debug("Store Successfully");
}
/**
* Store files in tree by search options.
* [Abandon]Please replace with the API of [storeFilesBySearchOptions]
* @param searchOption
* @param path
*/
private async storeFilesInTreeByOptions(
searchOption: SearchOptions,
path: string,
templatePath?: string
): Promise<any> {
const query = await this.generateQuery(searchOption);
//flatten response
//suite name is used to filter the search result
const response = await this.searchTestCasesByQuery(
query,
"TEST_SUITES",
searchOption.suiteName
);
//read template file
const fs = require("fs");
// if(!(templatePath === undefined)){
// var templateInfo = fs.readFileSync(templatePath,'utf8');
// }
//by suite name
if (response.length > 1) {
for (var i = 0; i < response.length; i++) {
const flatResponse = this.flat(response[i]);
const flatLength = flatResponse.length;
for (var j = 0; j < flatLength; j++) {
var tempKey = `${flatResponse[j].prefix}-${flatResponse[j].externalId}`;
await this.storeFileInTreeByCaseKey(tempKey, path, templatePath);
}
logger.debug(`Total Store ${flatLength} files`);
logger.debug("Store Successfully");
}
} else {
//not by suite name
const flatResponse = this.flat(response[0]);
const flatLength = flatResponse.length;
for (var i = 0; i < flatLength; i++) {
var tempKey = `${flatResponse[i].prefix}-${flatResponse[i].externalId}`;
await this.storeFileInTreeByCaseKey(tempKey, path, templatePath);
}
logger.debug(`Total Store ${flatLength} files`);
logger.debug("Store Successfully");
}
}
/**
* Store files by search option(use template render engine)
* @param searchOption
* @param path
* @param templatePath
*/
public async storeFilesBySearchOptions(
searchOption: SearchOptions,
path: string,
templatePath?: string
): Promise<any> {
//read template file (only read one time)
const fs = require("fs");
//make sure template path is true
var templateInfo: string;
if (templatePath === undefined) {
templateInfo = await fs.readFileSync(
"../templates/Default.txt",
"UTF-8",
function (err: any) {
throw new Error("Can't not find default.txt");
}
);
} else {
templateInfo = await fs.readFileSync(templatePath, "UTF-8", function (
err: any
) {
throw new Error(`Can't not find ${templatePath}`);
});
}
//if contains case id,search then return
if (!(searchOption.caseId === undefined)) {
const response = await this.getTestCaseByKey(searchOption.caseId);
const singleCaseInfo: CaseInfo = await this.fillCaseInfoMap(
searchOption.caseId,
response
);
await this.storeFileInTree(singleCaseInfo, path, templateInfo);
logger.debug(`Store ${searchOption.caseId} Successfully`);
return;
}
//generate query by search option(except suite name)
const query = await this.generateQuery(searchOption);
//suite name is used to filter the search result
const response = await this.searchTestCasesByQuery(
query,
"TEST_SUITES",
searchOption.suiteName
);
if (response.length == 0 || response == null)
throw new Error("Search for nothing");
//handle response and get all cases info
const cases: CaseInfo[] = await this.handleResponse(response);
const fileGenerateTask = [];
for (const item of cases) {
fileGenerateTask.push(
new Promise<void>(async resolve => {
await this.storeFileInTree(item, path, templateInfo);
resolve();
})
);
}
//Promise all storage
await Promise.all(fileGenerateTask);
logger.debug(
`[Store Finished] Total Store ${fileGenerateTask.length} files`
);
}
/**
* Handle search response to generate case info map
* @param response
*/
async handleResponse(response: any): Promise<CaseInfo[]> {
var caseInfoMap: CaseInfo[] = [];
const caseInfoSyncTask = [];
if (response.length > 1) {
for (var i = 0; i < response.length; i++) {
const flatResponse = this.flat(response[i]);
//if repeat suite name,clear case info map
for (const item of flatResponse) {
caseInfoSyncTask.push(
new Promise<void>(async resolve => {
var tempKey = `${item.prefix}-${item.externalId}`;
const caseResponse = await this.getTestCaseByKey(tempKey);
const caseInfo = await this.fillCaseInfoMap(
tempKey,
caseResponse
);
caseInfoMap.push(caseInfo);
resolve();
})
);
// logger.debug(`${caseInfoMap[0].ascendants} ----- Search result : ${flatResponse.length}`)
logger.debug(`Ready to store ${caseInfoMap.length} files`);
}
}
//get all caseInfo
await Promise.all(caseInfoSyncTask);
logger.debug(`Total Search : ${response.length} suite name tree`);
} else {
//not by suite name
const flatResponse = this.flat(response[0]);
const caseInfoSyncTask = [];
for (const item of flatResponse) {
caseInfoSyncTask.push(
new Promise<void>(async resolve => {
var tempKey = `${item.prefix}-${item.externalId}`;
const caseResponse = await this.getTestCaseByKey(tempKey);
const caseInfo = await this.fillCaseInfoMap(tempKey, caseResponse);
caseInfoMap.push(caseInfo);
resolve();
})
);
}
await Promise.all(caseInfoSyncTask);
logger.debug(`Ready to Store ${flatResponse.length} files`);
}
return caseInfoMap;
}
/**
* Fill case info map
* @param tempKey
* @param caseResponse
*/
private async fillCaseInfoMap(
tempKey: string,
caseResponse: any
): Promise<CaseInfo> {
var caseInfo = {
id: tempKey,
name: caseResponse.name,
suite: await this.fetchTemplateFieldInfo(caseResponse, "suite"),
priority: `P${caseResponse.priority}`,
ids: [tempKey],
ascendants: await this.fetchTemplateFieldInfo(caseResponse, "ascendants"),
keywords: await this.fetchTemplateFieldInfo(caseResponse, "keywords"),
maintainers: await this.fetchTemplateFieldInfo(
caseResponse,
"maintainers"
),
docs: await this.fetchTemplateFieldInfo(caseResponse, "docs"),
testSteps: await this.fetchTemplateFieldInfo(caseResponse, "testSteps"),
preconditions: await this.fetchTemplateFieldInfo(
caseResponse,
"preconditions"
),
accountType: await this.fetchTemplateFieldInfo(
caseResponse,
"accountType"
),
extensionType: await this.fetchTemplateFieldInfo(
caseResponse,
"extensionType"
),
entryPoint: await this.fetchTemplateFieldInfo(caseResponse, "entryPoint")
};
return caseInfo;
}
/**
* Search test cases by query.
* 【Query Example】const query = `version eq "active" and project_id in "[1311]" and field.5371560 in "[6234174]" and field.224 in "[11949947]"`;
* @param query
* @param scope
* @param suiteName use suite name to filter
*/
async searchTestCasesByQuery(
query: string,
scope: Scope = "TEST_SUITES",
suiteName?: string
): Promise<any> {
const queryJson = await this.generateSearchJson(query);
const response = await this.searchTestCasesByJsonQuery(queryJson, scope);
//handle the response by suite name
if (!(suiteName === undefined)) {
const filterResult = await this.SearchSuiteBlkInResponse(
response,
suiteName
);
return filterResult;
} else {
//not by suite name
const result = [];
result.push(response);
return result;
}
}
/**
* Search suite by suite name in response
* @param response
* @param suiteName
*/
private async SearchSuiteBlkInResponse(
response: any,
suiteName: string
): Promise<any> {
var suiteQueue = [];
var resultData = [];
// search from project
for (var i = 0; i < response.children.length; i++) {
var tempProject = response.children[i];
// handle temp project
if (!(tempProject.children === undefined)) {
// search suite by suite name(dfs)
for (var j = 0; j < tempProject.children.length; j++) {
suiteQueue.push(tempProject.children[j]);
while (suiteQueue.length != 0 && suiteQueue != null) {
var tempSuite: any = await suiteQueue.shift();
if (tempSuite === undefined) continue;
if (tempSuite.name == suiteName) {
resultData.push(tempSuite);
}
//search for suite children
if (
!(tempSuite.children === undefined) &&
tempSuite.type == "suite"
) {
for (var k = 0; k < tempSuite.children.length; k++) {
if (tempSuite.children[k].type == "suite") {
suiteQueue.push(tempSuite.children[k]);
}
}
}
}
}
}
}
return resultData;
}
/**
* Convert search query to json.
* @param query
*/
private async generateSearchJson(query: string): Promise<any> {
const queryParse = Parser.parse(query);
// logger.debug(queryParse);
var queryJson = await JSON.stringify(queryParse);
//Handle the queryJson.
const s1 = '\\"';
queryJson = queryJson.replace(s1, "").replace(s1, "");
queryJson = queryJson.replace(/\"\\\"/g, "").replace(/\\\"\"/g, "");
//filter search condition of suiteName value
queryJson = queryJson.replace(/'/g, '"');
// logger.debug(queryJson);
return queryJson;
}
/**
* Search testCases by search options(projectName,keywords,subtype).
* @param projectName
* @param keywords
* @param subtype
*/
public async searchCasesBySearchOptions(
searchOption: SearchOptions
): Promise<any> {
//if search options constain search id
if (!(searchOption.caseId === undefined)) {
const response = await this.getTestCaseByKey(searchOption.caseId);
await this.printSearchInfo(response);
return;
}
//ToQuery
const query = await this.generateQuery(searchOption);
const searchRes = await this.searchTestCasesByQuery(
query,
"TEST_SUITES",
searchOption.suiteName
);
//count response lenth
//by suite name
if (searchRes.length > 1) {
const flatResponseArr = [];
logger.debug(
`->> Find ${searchRes.length} suites according to the ${searchOption.suiteName}`
);
for (var i = 0; i < searchRes.length; i++) {
const flatResponse = this.flat(searchRes[i]);
logger.debug(`Search Result: `);
this.printSearchInfo(flatResponse);
flatResponseArr.push(flatResponse);
logger.debug(`Total Search : ${flatResponse.length}\n`);
}
return flatResponseArr; //return array
} else {
//not by suite name
logger.debug(
`->> Find 1 suite according to the ${searchOption.suiteName}`
);
const flatResponse = this.flat(searchRes[0]);
logger.debug(`Search Result: `);
this.printSearchInfo(flatResponse);
logger.debug(`Total Search : ${flatResponse.length}`);
return flatResponse; // return response
}
}
/**
* Print search result info
* @param flatResponse
*/
private async printSearchInfo(flatResponse: any): Promise<any> {
for (var i = 0; i < flatResponse.length; i++) {
const temp = flatResponse[i];
var info = `\t${temp.prefix}-${temp.externalId}:${temp.name}`;
logger.debug(info);
}
}
/**
* Get suite id by name.
* @param suiteName
* @param projectId
*/
private async getSuiteIdByName(
suiteName: string,
projectId: number
): Promise<number[]> {
const projectTree = await this.getProjectTreeById(projectId);
// get suite id by suite name(bfs)
var searchQueue: any = [];
var suiteId: number[] = [];
for (var i = 0; i < projectTree.length; i++) {
await searchQueue.push(projectTree[i]);
// logger.debug(i);
// traverse first level
while (searchQueue.length != 0 && searchQueue != null) {
var tempSuite = await searchQueue.shift();
if (tempSuite === undefined) continue;
try {
if (tempSuite.name == suiteName) {
//store suiteId
suiteId.push(tempSuite.id);
}
} catch (err) {
logger.debug(tempSuite);
}
// has children
if (!(tempSuite.children === undefined) && tempSuite.type == "suite") {
for (var j = 0; j < tempSuite.children.length; j++) {
if (tempSuite.children[j].type == "suite") {
await searchQueue.push(tempSuite.children[j]);
}
}
}
}
}
return suiteId;
}
/**
* Search cases by suite name.
* [Abandon]
* @param suiteName
* @param projectName
*/
private async searchCasesBySuiteName(
suiteName: string,
projectName: string
): Promise<any> {
const projectId = await this.getProjectIdByName(projectName);
const caseKeyMap = [];
// get project prefix map
const prefixMap = await this.genPrefixProjectMap();
const prefix = await prefixMap.get(projectId);
// get suite id by suite name(bfs)
const suiteId = await this.getSuiteIdByName(suiteName, projectId);
logger.debug(suiteId);
// get suite tree by id and flat it get total case
logger.debug(`Search for ${suiteId.length} suite`);
for (var k = 0; k < suiteId.length; k++) {
// get suite tree and suite
const suiteTree = await this.getSuiteTreeById(suiteId[k]);
const suite = await this.getSuiteById(suiteId[k]);
// get the store path by suite
var path = "";
for (var i = 0; i < suite.ascendants.length; i++) {
path = `${path}${suite.ascendants[i].name}/`;
}
logger.debug(`The path : ${path}`);
// handle the flatten response
for (var i = 0; i < suiteTree.length; i++) {
var flatResponse = await this.flat(suiteTree[i]);
for (var j = 0; j < flatResponse.length; j++) {
var caseKeyInfo = `${prefix}-${flatResponse[j].externalId}`;
logger.debug(caseKeyInfo);
caseKeyMap.push(caseKeyInfo);
}
}
}
logger.debug(`Total Search Result : ${caseKeyMap.length}`);
return caseKeyMap;
}
/**
* Store cases by suite name.
* [Abandon]
* @param suiteName
* @param projectName
* @param path
*/
private async storeCasesBySuiteName(
suiteName: string,
projectName: string,
path: string,
templatePath?: string
): Promise<any> {
const caseKeyMap = await this.searchCasesBySuiteName(
suiteName,
projectName
);
for (var i = 0; i < caseKeyMap.length; i++) {
await this.storeFileInTreeByCaseKey(caseKeyMap[i], path, templatePath);
}
}
/**
* Generate search query by project name、keywords and suite.
* @param projectName
* @param keywords
* @param subtype
*/
async generateQuery(searchOption: SearchOptions): Promise<string> {
//get option params
const projectName = searchOption.projectName;
const projectId = await this.getProjectIdByName(projectName);
//Fetch fields info
const response = await this.fetchFieldsInfoById(projectId);
//Generate map
const keyworsMap = await this.getFieldsInfoMapByName(response, "Keywords");
const subtypeMap = await this.getFieldsInfoMapByName(response, "Subtype");
const automatedByMap = await this.getFieldsInfoMapByName(
response,
"Automated By"
);
const fieldsIdMap = await this.getFieldsIdMap(response);
// Object.keys(searchOption).forEach((key)=>{
// console.log(searchOption.key);
// console.log(searchOption[key]);
// });
//For key Map
var keyWordQuery = "";
if (!(searchOption.keywords === undefined)) {
const keywords = searchOption.keywords;
var keywordsArr = [];
for (var i = 0; i < keywords.length; i++) {
keywordsArr.push(keyworsMap.get(keywords[i]));
}
keyWordQuery = `${keyWordQuery} and field.${fieldsIdMap.get(
"Keywords"
)} in "[${keywordsArr}]"`;
}
//For Suite Map
var subtypeQuery = "";
if (!(searchOption.subtype === undefined)) {
const subtype = searchOption.subtype;
var subtypeArr = [];
for (var i = 0; i < subtype.length; i++) {
subtypeArr.push(subtypeMap.get(subtype[i]));
}
subtypeQuery = `${subtypeQuery} and field.${fieldsIdMap.get(
"Subtype"
)} in "[${subtypeArr}]"`;
}
//Handle suite query
// var suiteQuery = "";
// if (!(searchOption.suiteName === undefined)) {
// const suiteName = searchOption.suiteName;
// suiteQuery = `${suiteQuery} and suite_name like "'${suiteName}'"`;
// }
//Handle priority query
var priorityQuery = "";
if (!(searchOption.priority === undefined)) {
const priority = searchOption.priority;
priorityQuery = `${priorityQuery} and priority in "[${searchOption.priority}]"`;
}
// handle case name query
var caseNameQuery = "";
if (!(searchOption.caseName === undefined)) {
const caseName = searchOption.caseName;
caseNameQuery = `${caseNameQuery} and case_name like "'${caseName}'"`;
}
// handle automatedBy by query
var automatedByQuery = "";
if (!(searchOption.automatedBy === undefined)) {
const automatedBy = searchOption.automatedBy;
var automatedByArr = [];
for (var i = 0; i < automatedBy.length; i++) {
automatedByArr.push(automatedByMap.get(automatedBy[i]));
}
automatedByQuery = `${automatedByQuery} and field.${fieldsIdMap.get(
"Automated By"
)} in "[${automatedByArr}]"`;
}
// handle date created
var dateCreatedQuery = "";
if (!(searchOption.dateCreated === undefined)) {
const dateCreated = searchOption.dateCreated;
const dateValue: number[] = [];
const timeZone = new Date().getTimezoneOffset() * 60 * 1000;
dateValue[0] = new Date(dateCreated[0]).getTime() + timeZone;
dateValue[1] = new Date(dateCreated[1]).getTime() + timeZone;
dateCreatedQuery = `${dateCreatedQuery} and date_created gte "${dateValue[0]}" and date_created lt "${dateValue[1]}"`;
}
// handle date updated
var dateUpdatedQuery = "";
if (!(searchOption.dateUpdated === undefined)) {
const dateUpdated = searchOption.dateUpdated;
const dateValue: number[] = [];
const timeZone = new Date().getTimezoneOffset() * 60 * 1000;
dateValue[0] = new Date(dateUpdated[0]).getTime() + timeZone;
dateValue[1] = new Date(dateUpdated[1]).getTime() + timeZone;
dateUpdatedQuery = `${dateUpdatedQuery} and last_updated gte "${dateValue[0]}" and last_updated lt "${dateValue[1]}"`;
}
//ToQuery
const query = `version eq "active" and project_id in "[${projectId}]"${keyWordQuery}${subtypeQuery}${priorityQuery}${caseNameQuery}${automatedByQuery}${dateCreatedQuery}${dateUpdatedQuery}`;
return query;
}
/* Sync API */
/**
* Get sync projects.
*/
public async getSyncProjects(): Promise<any> {
const url = `${this.endpoint}/api/internal/sync/projects`;
const headers = {
Authorization: this.accessToken,
"Content-type": "application/json"
};
const config = { headers };
const response = await this.httpClient.get(url, config);
return response.data;
}
/**
* Get sync cases.
*/
public async getSyncCases(): Promise<any> {
const url = `${this.endpoint}/api/internal/sync/cases`;
const headers = {
Authorization: this.accessToken,
"Content-type": "application/json"
};
const config = { headers };
const response = this.httpClient.get(url, config);
return response;
}
/* Get Store API */
/**
* Get store project by project id.
* @param projectId
*/
public async getStoreProjectById(projectId: number): Promise<any> {
const url = `${this.endpoint}/api/internal/storage/project/${projectId}`;
const headers = {
Authorization: this.accessToken,
"Content-type": "application/json"
};
const config = { headers };
const response = await this.httpClient.get(url, config);
return response.data;
}
/**
* Get global data.
* @return {Promise<IGlobalData>}
*/
public async getGlobalData(): Promise<IGlobalData> {
const url = `${this.endpoint}/projects/static`;
const headers = {
Authorization: this.accessToken,
"Content-Type": "application/json"
};
const config = { headers };
const response = await this.httpClient.get(url, config);
return response.data;
}
/**
* Search for suggest cases by query.
* @param pattern
* @param limit
*/
public async getSuggestTestCases(
pattern: string,
limit: number = 10
): Promise<IGetSuggestTestCasesResponseDTO> {
const url = `${this.endpoint}/api/v1/suggest/cases?search=${pattern}&limit=${limit}`;
const headers = {
Authorization: this.accessToken,
"Content-Type": "application/json"
};
const config = { headers };
const response = await this.httpClient.get(url, config);
return response.data;
}
public async generateInfosByKey(key: string): Promise<any> { }
/**
* Generate template info by key according to giving template
* @param key
* @param templatePath
*/
public async generateInfoByKeyInTemplate(
key: string,
templatePath: string
): Promise<string> {
const fs = require("fs");
const responseData = await this.getTestCaseByKey(key);
//read template
var templateInfo = fs.readFileSync(templatePath, "utf8");
//1.handle basic info
//extract match fields that need to fill
const matchRes = templateInfo.match(/.*[\n\t\s]*\$\{.*?\}[\n\t\s]*.*/g);
//fill template info
for (var i = 0; i < matchRes.length; i++) {
const field = matchRes[i].split(":")[0].trim();
// logger.debug(field);
//get info
const info = await this.fetchTemplateFieldInfo(responseData, field);
//replace
if (!(info === undefined)) {
templateInfo = await templateInfo.replace(/\$\{.*?\}/, info);
}
}
//2.handle test steps info
const matchResTs = templateInfo.match(/.*\$\{.*?\}.*[\n\s\t\r]*.*/g);
var childrenLen = responseData.children.length;
var contentInfo = `${matchResTs[0]}\n${matchResTs[1]}\n`;
// expand info
var expandInfo = "";
for (var i = 0; i < childrenLen; i++) {
expandInfo = `${expandInfo}${contentInfo}`;
}
templateInfo = templateInfo.replace(
`${matchResTs[0]}\n${matchResTs[1]}`,
expandInfo
);
//extract testSteps info
var steps = [];
var expectedResult = [];
if (childrenLen != 0) {
for (var i = 0; i < childrenLen; i++) {
steps[i] = await this.stringFilter(responseData.children[i].name);
expectedResult[i] = await this.stringFilter(
responseData.children[i].expectedResult
);
}
}
//fill test steps
for (var i = 0; i < childrenLen; i++) {
templateInfo = templateInfo
.replace("${}", steps[i])
.replace("${}", expectedResult[i]);
}
return templateInfo;
}
public async getTestStepsInfo() { }
/**
* Fetch template field information by field name
* To fill template
* @param responseData
* @param field
*/
public async fetchTemplateFieldInfo(
responseData: any,
field: string
): Promise<any> {
const key = `${responseData.prefix}-${responseData.externalId}`;
// logger.debug(matchInfo);
// var accountType = (info[0].split(":"))[1].trim();
// var entryPoint = (info[1].split(":")[1]).trim();
if (field == "suite") {
const ascendantsLen = responseData.ascendants.length;
const suiteInfo = responseData.ascendants[ascendantsLen - 1].name;
return suiteInfo;
} else if (field == "name") {
const name = `${key}:${responseData.name}`;
return name;
} else if (field == "keywords") {
const valueLen = responseData.values.length;
const keywords = [];
for (var i = 0; i < valueLen; i++) {
// 224 is keywords field id
if (responseData.values[i].fieldId == 224) {
keywords.push(responseData.values[i].name);
}
}
// var keywordsStr = await this.convertoString(keywords);
// return keywordsStr;
return keywords;
} else if (field == "priority") {
const casePrioriy = `P${responseData.priority}`;
return casePrioriy;
} else if (field == "maintainers") {
const valueLen = responseData.values.length;
const maintainers = [];
for (var i = 0; i < valueLen; i++) {
// 6615030 is keywords field id
if (responseData.values[i].fieldId == 6615030) {
maintainers.push(responseData.values[i].name);
}
}
// var maintainersStr = await this.convertoString(maintainers);
// return maintainersStr;
return maintainers;
} else if (field == "docs") {
var docsArr = [];
var url = await `${this.endpoint}/test-cases/${key}`;
docsArr.push(url);
var docs = this.convertoString(docsArr);
return docs;
} else if (field == "ids") {
const ids = key;
return ids;
} else if (field == "subtype") {
const valueLen = responseData.values.length;
const subtype = [];
for (var i = 0; i < valueLen; i++) {
// 6231852 is keywords field id
if (responseData.values[i].fieldId == 6231852) {
subtype[i] = responseData.values[i].name;
}
}
var subtypeStr = await this.convertoString(subtype);
return subtypeStr;
} else if (field == "testSteps") {
const children = responseData.children;
const childrenLen = children.length;
var testStepsInfo: stepsInfo[] = [];
for (var i = 0; i < childrenLen; i++) {
testStepsInfo[i] = {
step: await this.stringFilter(children[i].name),
expectedResult: await this.stringFilter(children[i].expectedResult)
};
}
return testStepsInfo;
} else if (field == "ascendants") {
const ascendants = responseData.ascendants;
var suiteTree = "";
for (var i = 0; i < ascendants.length; i++) {
var tempName = ascendants[i].name;
// delete space
const space = new RegExp(" ", "g");
tempName = tempName.replace(space, "");
suiteTree = `${suiteTree}/${tempName}`;
}
suiteTree = suiteTree.replace(suiteTree.charAt(0), "");
return suiteTree;
}
//handle preconditions
var preconditions = await this.stringFilter(responseData.preconditions);
const matches = preconditions.match(/Account type\(\/s\)\:[ ]*.*/);
var matchInfo: any[];
//no matches
if (matches === undefined || matches === null) {
return;
} else {
//match by special (/s):
matchInfo = matches[0].split("(/s):");
}
if (field == "preconditions") {
return preconditions;
} else if (field == "accountType") {
//return accountType
const accountType = matchInfo[1].replace("Extension type", "").trim();
return accountType;
} else if (field == "extensionType") {
//return extensionType
const extensionType = matchInfo[2].replace("Entry point", "").trim();
return extensionType;
} else if (field == "entryPoint") {
//return entryPointStr
const entryPointStr = matchInfo[3].trim();
return entryPointStr;
}
}
/**
* Convert original array to string
* @param original
*/
private async convertoString(original: any[]): Promise<string> {
var result = "";
for (var i = 0; i < original.length; i++) {
result = `${result}"${original[i]}",`;
}
result = result.substring(0, result.length - 1);
return result;
}
/**
* Generate template information by key.
* @param key Case key
*/
public async generateTemplatesInfoByKey(key: string): Promise<string> {
const responseData = await this.getTestCaseByKey(key);
const ascendantsLen = responseData.ascendants.length;
const suite = responseData.ascendants[ascendantsLen - 1].name;
const nameInfo = `${key}:${responseData.name}`;
const casePrioriy = `P${responseData.priority}`;
const skip = true; //default
const skipReason = "waiting for E2E deliver"; //default
const keywords = [];
const maintainers = [];
const valueLen = responseData.values.length;
//Refer to field id.
for (var i = 0; i < valueLen; i++) {
if (responseData.values[i].fieldId == 224) {
keywords.push(responseData.values[i].name);
} else if (responseData.values[i].fieldId == 6615030) {
maintainers.push(responseData.values[i].name);
}
}
//Handle the test steps info.
var childrenLen;
var steps = [];
var expectedResult = [];
if ((childrenLen = responseData.children.length) != 0) {
for (var i = 0; i < childrenLen; i++) {
steps[i] = await this.stringFilter(responseData.children[i].name);
expectedResult[i] = await this.stringFilter(
responseData.children[i].expectedResult
);
}
}
//some str to connect the data.
const importInfo = `import { h, runTest } from '@src/init';\nimport { App } from "@src/pageModels/app";\nimport { StepWrapper } from "@tests/stepWrapper";\nimport { HomePageController } from "@src/pageControllers/app/homePage";\nimport MeetingRoomController from "@src/pageControllers/app/homePage/meetingRoom";\nimport { WebphoneSession } from "ultron-client";\nimport { LeftRailController } from "@src/pageControllers/app/homePage/meetTab";\nimport MeetingPageController from '@src/pageControllers/app/homePage/meetingPage';\nimport { sleep } from "@src/libs/utils";\n`;
const runTestInfo = "runTest({\n";
const asyncInfo = "},async(t:any)=>{\n";
const preStep = '\tawait h(t).When_("';
const afterStep = ",async()=>{\n\t});\n";
const preExpect = '\tawait h(t).Then_("';
const afterExpect = ",async() => {\n\t});\n";
const end = "\th(t).finish();\n});";
//storage template info.
var resInfo: TemplateInfo = {
suite: suite,
name: [nameInfo],
priority: casePrioriy,
skip: skip,
skipReason: skipReason,
keywords: keywords,
maintainers: maintainers
};
// handle resInfo
var resInfoStr = JSON.stringify(resInfo);
const resInfoKeys = Object.keys(resInfo); //get keys
for (var i = 0; i < resInfoKeys.length; i++) {
resInfoStr = resInfoStr.replace(`"${resInfoKeys[i]}"`, resInfoKeys[i]);
resInfoStr = resInfoStr.replace(
`,${resInfoKeys[i]}`,
`,\n${resInfoKeys[i]}`
);
}
// delete the character of start and end
resInfoStr = resInfoStr.replace(resInfoStr.charAt(0), "");
resInfoStr = resInfoStr.replace(
resInfoStr.charAt(resInfoStr.length - 1),
""
);
// add tab
for (var i = 0; i < resInfoKeys.length; i++) {
resInfoStr = resInfoStr.replace(
`${resInfoKeys[i]}`,
`\t${resInfoKeys[i]}`
);
}
// put together
var resultInfo = `${importInfo}${runTestInfo}${resInfoStr}\n${asyncInfo}`;
for (var i = 0; i < childrenLen; i++) {
resultInfo = `${resultInfo}${preStep}${steps[i]}"${afterStep}${preExpect}${expectedResult[i]}"${afterExpect}`;
}
resultInfo = `${resultInfo}${end}`;
return resultInfo;
}
/**
* Write info to ouputstream and storage to file path.
* @param info
* @param filePath
*/
public async writeTemplateInfo(info: string, filePath: string): Promise<any> {
var fs = require("fs");
var infoWriteStream = fs.createWriteStream(filePath);
infoWriteStream.write(info, "UTF-8");
infoWriteStream.end();
infoWriteStream.on(`${filePath}--Done`, () => {
logger.debug("${filePath}--Done");
});
// infoWriteStream.on('error',function(err:any){
// logger.debug(err.stack);
// });
}
/**
* Store a template file to file path by case key.
* @param key
* @param filePath
*/
public async storeTemplateInfoByCaseKey(key: string, filePath: string) {
const info = await this.generateTemplatesInfoByKey(key);
filePath = `${filePath}${key}.test.ts`;
this.writeTemplateInfo(info, filePath);
}
/**
* Store template info for file tree by case key.
* @param key
* @param filePath
*/
private async storeFileInTreeByCaseKey(
key: string,
filePath: string,
templatePath?: string
) {
const response = await this.getTestCaseByKey(key);
const ascendants = response.ascendants;
var suiteTree = "";
for (var i = 0; i < ascendants.length; i++) {
var tempName = ascendants[i].name;
// delete space
const space = new RegExp(" ", "g");
tempName = tempName.replace(space, "");
suiteTree = `${suiteTree}/${tempName}`;
}
suiteTree = suiteTree.replace(suiteTree.charAt(0), "");
filePath = `${filePath}${suiteTree}`;
this.writeInfoByCreateDir(key, filePath, templatePath);
}
/**
* Store file by case key
* @param key
* @param filePath
* @param templatePath
*/
public async storeFileByCaseKey(
key: string,
filePath: string,
templatePath?: string
) {
const response = await this.getTestCaseByKey(key);
const caseInfo = await this.fillCaseInfoMap(key, response);
const fs = require("fs");
var templateInfo;
//make sure template path is true
if (templatePath === undefined) {
templateInfo = fs.readFileSync(
"../templates/Default.txt",
"UTF-8",
function (err: any) {
throw new Error("Can't not find default.txt");
}
);
} else {
templateInfo = fs.readFileSync(templatePath, "UTF-8", function (err: any) {
throw new Error(`Can't not find ${templatePath}`);
});
}
await this.storeFileInTree(caseInfo, filePath, templateInfo);
}
/**
* Store and fill templateInfo
* @param caseInfo
* @param filePath
* @param templateInfo
*/
async storeFileInTree(
caseInfo: CaseInfo,
filePath: string,
templateInfo: string
): Promise<any> {
var resultInfo = templateInfo;
filePath = `${filePath}${caseInfo.ascendants}`;
var fileName = `${filePath}/${caseInfo.id}.test.ts`;
//use mustache to render template
const Mustache = require("mustache");
Mustache.parse(templateInfo);
resultInfo = Mustache.render(templateInfo, caseInfo);
// logger.debug(resultInfo);
// logger.debug(filePath);
//write resultInfo into path
await this.writeInfo(resultInfo, filePath, fileName);
}
/**
* Write info by create dir.
* @param info
* @param filePath
*/
private async writeInfoByCreateDir(
key: string,
filePath: string,
templatePath?: string
): Promise<any> {
// get template info
var info;
if (!(templatePath === undefined)) {
info = await this.generateInfoByKeyInTemplate(key, templatePath);
} else {
info = await this.generateTemplatesInfoByKey(key);
}
// create directory
const mkdirp = require("mkdirp");
await mkdirp(filePath); //.then((made: any) => logger.debug(`Create in ${made}`));
// store info
var fs = require("fs");
const testFile = `${filePath}/${key}.test.ts`;
logger.debug(`Store ${testFile}`);
var infoWriteStream = await fs.createWriteStream(testFile);
await infoWriteStream.write(info, "UTF-8");
await infoWriteStream.end();
infoWriteStream.on(`${filePath}--Done`, () => {
logger.debug("${filePath}--Done");
});
infoWriteStream.on("error", function (err: any) {
logger.debug(err.stack);
});
}
private async writeInfo(
info: string,
filePath: string,
fileName: string
): Promise<any> {
const mkdirp = require("mkdirp");
await mkdirp(filePath); //.then((made: any) => logger.debug(`Create in ${made}`));
// store info
var fs = require("fs");
logger.debug(`Store ${fileName}`);
var infoWriteStream = await fs.createWriteStream(fileName);
await infoWriteStream.write(info, "UTF-8");
await infoWriteStream.end();
infoWriteStream.on(`${fileName}--Done`, () => {
logger.debug("${fileName}--Done");
});
infoWriteStream.on("error", function (err: any) {
logger.debug(err.stack);
});
}
/**
* Make directory.
* @param dir
*/
private async mkdir(dir: any) {
const fs = require("fs");
fs.mkdir(dir, (err: any) => {
if (err) {
logger.debug(err);
return;
}
});
}
/**
* Filter string with special character.
* @param str
*/
private async stringFilter(str: string): Promise<any> {
if (str != null) {
const newLine = "\n[\n]*";
const quota = '"';
str = await str
.replace(new RegExp("<.*?>", "g"), "")
.replace(new RegExp(newLine, "g"), " ")
.replace(new RegExp(quota, "g"), "'"); // RegExp = "\<.*?\>" all block
str = str.trim();
str = unescape(str); //url
// str = decodeURIComponent(str);//uri
str = await this.htmlDecodeByRegExp(str); //html tags
}
return str;
}
private async htmlDecodeByRegExp(str: string): Promise<string> {
if (str.length == 0) return "";
str = await str
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/ /g, " ")
.replace(/'/g, "'")
.replace(/"/g, '"');
return str;
}
}
// // /**
// // * Test Modules
// // */
// async function testitDemo() {
// /* Login require information */
// const TESTIT_ENDPOINT = "https://testit.ringcentral.com";
// const testItSdk = new TestItSDK(TESTIT_ENDPOINT);
// // const username: string = process.env.USERNAME;
// // const password: string = process.env.PASSWORD;
// // await testItSdk.searchCasesBySearchOptions(searchOption);
// /* 1、Test login function. */
// // logger.debug(USERNAME);
// // logger.debug(USERNAME);
// //config my debug
// const log4js = require('log4js');
// log4js.configure({
// appenders: { console: { type: 'console' } },
// categories: { default: { appenders: ['console'], level: 'debug' } }
// });
// await testItSdk.login(USERNAME, PASSWORD);
// const searchOption: SearchOptions = {
// projectName: "Jupiter",
// subtype:["E2E"],
// dateCreated :["2021-01-01","2021-01-10"],
// dateUpdated :["2021-01-01","2021-01-10"]
// };
// // var output = Mustache.render("{{title}} sßpends {{calc}}", view);
// // logger.debug(output);
// const path = "../templateFiles/";
// const templatePath = "../templates/JupiterTemplate.ts.txt";
// // await testItSdk.searchCasesBySearchOptions(searchOption);
// // await testItSdk.storeFileByCaseKey("JPT-5660",path,templatePath);
// // await testItSdk.searchCasesBySearchOptions(searchOption);
// await testItSdk.storeFilesBySearchOptions(searchOption, path, templatePath);
// }
// testitDemo();