This repository was archived by the owner on Nov 19, 2020. It is now read-only.
forked from jkamepalli/PulseRules_v9.1
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathUpdateDescriptionPreconditionAndPrettify.js
203 lines (161 loc) · 6.57 KB
/
UpdateDescriptionPreconditionAndPrettify.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
const PulseSdk = require('@qasymphony/pulse-sdk');
// @pure
const isBackground = ({ keyword }) => keyword.toLowerCase() === 'background';
// @pure
const getHeaders = (token) => ({
'Content-Type': 'application/json',
'Authorization': `bearer ${token}`
});
// @pure
const convertKeywordAndNameToParagraph = (keyword, name) =>
`<p><span style='color: #808000;;'><strong>${keyword}:</strong></span> ${name}</p>`;
// @pure
const convertStepToSpanWithBreak = ({ description, expected_result }) =>
`<span style='color: #008080; padding-left: 10px'><strong>${description}</strong></span>${expected_result}<br>`;
// @pure
const convertDescriptionToParagraph = description => `<p style='padding-left: 10px'><em>${description}</em></p>`;
// @pure
const convertStepLogsToPrecondition = ({ keyword, name, description, test_step_logs }) => {
const header = convertKeywordAndNameToParagraph(keyword, name);
const summary = (description !== "") ? convertDescriptionToParagraph(description) : "";
const paragraphs = test_step_logs.map(convertStepToSpanWithBreak);
return `${header}${summary}${paragraphs.join("")}`;
};
// @pure
const isDuplicateField = (item, index, array, property) => array.map(object => object[property])
.indexOf(item[property]) !== index;
// @pure
const removingDuplicatesCausedByScenarioOutlines = (item, index, arr) => {
const isDuplicateName = isDuplicateField(item, index, arr, "name");
const isDuplicateFeatureName = isDuplicateField(item, index, arr, "featureName");
return !(isDuplicateName && isDuplicateFeatureName);
};
// @pure
const isNotABackgroundAndHasAMatchingFeatureName = ({ keyword, featureName }, nameToMatch) =>
(featureName === nameToMatch) && (keyword.toLowerCase() !== 'background');
// @pure
const getSearchUrl = (managerUrl, projectId) => `${managerUrl}/api/v3/projects/${projectId}/search`;
// @pure
const getApproveTestCaseUrl = (managerUrl, projectId, id) => `${managerUrl}/api/v3/projects/${projectId}/test-cases/${id}/approve`
// @pure
const getSearchBody = name => ({
object_type: "test-cases",
fields: ["id", "test_steps"],
query: `name = '${name}'`
});
// @pure
const getUpdateTestCaseUrl = (managerUrl, projectId, id) => `${managerUrl}/api/v3/projects/${projectId}/test-cases/${id}`;
// @pure
const formatDescriptionIfNotEmpty = description => description !== "" ? convertDescriptionToParagraph(description) : "";
// @pure
const getUpdateTestCaseBody = (precondition, description) => ({
precondition: precondition,
description: formatDescriptionIfNotEmpty(description)
});
// @pure
const sleep = milliSeconds => new Promise(
resolve => setTimeout(resolve, milliSeconds)
);
// @impure: mutable
const State = {
projectId: null,
managerUrl: null,
qTestToken: null,
logs: null
};
// @impure: reliant on network and mutable state
const performApiCall = async function(url, method, body) {
const { qTestToken } = State;
const payload = {
method: method,
headers: getHeaders(qTestToken),
body: JSON.stringify(body)
}
const response = await fetch(url, payload);
return response.json();
};
// @impure: reliant on network and mutable state
const performApiCallEmptyBody = async function(url, method) {
const { qTestToken } = state;
const payload = {
method: method,
headers: getHeaders(qTestToken)
}
const response = await fetch(url, payload);
return response.json();
};
// @impure: reliant on network and mutable state and uses I/O
const getTestCaseId = async function({ name }) {
const { managerUrl, projectId } = State;
const url = getSearchUrl(managerUrl, projectId);
const body = getSearchBody(name);
let resbody = await performApiCall(url, "POST", body);
// Implement retry logic to handle the delay when a new test case is created
for (let attempt = 1; attempt <= 10 && resbody.items.length === 0; attempt++) {
console.log(`Retrying to get matching test cases, attempt (${attempt})...`);
await sleep(5000);
resbody = await performApiCall(url, "POST", body);
}
if (resbody.items.length === 0) {
return Promise.reject(`Failed to return a matching test case for '${name}'`);
}
return Promise.resolve(resbody.items[0].id);
};
// @impure: reliant on network and mutable state
const updateAllTestCases = async function(testCase) {
const { precondition } = this;
const { description } = testCase;
const id = await getTestCaseId(testCase);
return await updateTestCaseFields(id, precondition, description);
};
// @impure: reliant on network and mutable state
const approveAllTestCases = async function(testCase) {
const { managerUrl, projectId } = State;
const id = await getTestCaseId(testCase);
const url = await getApproveTestCaseUrl(managerUrl, projectId, id);
return await performApiCallEmptyBody(url, "PUT");
};
// @impure: reliant on network and mutable state
const updateTestCaseFields = async function(id, precondition, description) {
const { managerUrl, projectId } = State;
const url = getUpdateTestCaseUrl(managerUrl, projectId, id);
const body = getUpdateTestCaseBody(precondition, description);
return await performApiCall(url, "PUT", body);
};
// @impure: reliant on network and mutable state
async function generatePreconditionAndPostToManager(background) {
const { logs } = State;
const nameToMatch = background.featureName;
const precondition = { precondition: convertStepLogsToPrecondition(background) };
const matchingTestCases = logs.filter(
log => isNotABackgroundAndHasAMatchingFeatureName(log, nameToMatch)
);
const updates = await Promise.all(
matchingTestCases.map(updateAllTestCases, precondition)
);
const approvals = await Promise.all(
matchingTestCase.map(approveAllTestCases)
);
return updates.concat(approvals);
};
// Entry point to the script
// @impure: reliant on network and uses I/O
exports.handler = async function({ event: body, constants, triggers }, context, callback) {
const { logs, projectId } = body;
const { ManagerURL, QTEST_TOKEN } = constants;
const backgrounds = logs.filter(isBackground)
.filter(removingDuplicatesCausedByScenarioOutlines);
State.projectId = projectId;
State.managerUrl = ManagerURL;
State.qTestToken = QTEST_TOKEN;
State.logs = logs;
try {
await Promise.all(
backgrounds.map(generatePreconditionAndPostToManager)
);
console.log("Successfully updated all test cases");
} catch (error) {
console.log(error);
}
console.log("End of job");
};