itemengine-cypress-automation 1.0.519-dependabot-npm-and-yarn-multi-92087b3b2d-4281f2d.0 → 1.0.519
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Dockerfile +0 -1
- package/deploy/audioResponseQuestion/service.yaml +2 -4
- package/il.yaml +1 -0
- package/package.json +4 -2
- package/scripts/run-status-check.mjs +211 -0
- package/scripts/sorry-cypress.mjs +7 -1
package/Dockerfile
CHANGED
@@ -5,14 +5,12 @@ global:
|
|
5
5
|
enabled: true
|
6
6
|
highestEnvironment: dev
|
7
7
|
|
8
|
-
env:
|
9
|
-
- name: STAGE
|
10
|
-
value: "dev"
|
11
|
-
|
12
8
|
deployment:
|
13
9
|
activeDeadlineSeconds: 28800
|
14
10
|
architecture: amd64
|
15
11
|
restartPolicy: Never
|
12
|
+
parallelism: 7
|
13
|
+
completions: 7
|
16
14
|
image:
|
17
15
|
cmd: /ie-e2e/deploy/audioResponseQuestion/run.sh
|
18
16
|
buildContext: ../..
|
package/il.yaml
CHANGED
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "itemengine-cypress-automation",
|
3
|
-
"version": "1.0.519
|
3
|
+
"version": "1.0.519",
|
4
4
|
"description": "",
|
5
5
|
"main": "index.js",
|
6
6
|
"scripts": {
|
@@ -39,12 +39,14 @@
|
|
39
39
|
"dependencies": {
|
40
40
|
"@cypress/grep": "^3.1.5",
|
41
41
|
"axe-core": "^4.7.1",
|
42
|
+
"axios": "^1.12.2",
|
42
43
|
"cy-verify-downloads": "^0.1.11",
|
43
44
|
"cy2": "^4.0.9",
|
44
|
-
"cypress": "^
|
45
|
+
"cypress": "^12.17.2",
|
45
46
|
"cypress-axe": "^1.4.0",
|
46
47
|
"cypress-file-upload": "^5.0.8",
|
47
48
|
"cypress-real-events": "^1.7.6",
|
49
|
+
"dotenv": "^17.2.2",
|
48
50
|
"node-fetch": "^3.3.2",
|
49
51
|
"react-uuid": "^2.0.0",
|
50
52
|
"typescript": "^5.6.3"
|
@@ -0,0 +1,211 @@
|
|
1
|
+
import axios from "axios";
|
2
|
+
|
3
|
+
const sorryCypressTimeout = 1800000;
|
4
|
+
const graphqlUrl = "https://cypress-api.imaginelearning.tech/";
|
5
|
+
const projectId = "imaginelearning/itemengine-edgeex-cypress-automation";
|
6
|
+
|
7
|
+
function getProjectId() {
|
8
|
+
return process.env.CYPRESS_PROJECT_ID || projectId;
|
9
|
+
}
|
10
|
+
|
11
|
+
function getRunsRequest() {
|
12
|
+
return {
|
13
|
+
operationName: "getRunsFeed",
|
14
|
+
variables: {
|
15
|
+
filters: [
|
16
|
+
{
|
17
|
+
key: "meta.projectId",
|
18
|
+
value: getProjectId(),
|
19
|
+
like: null,
|
20
|
+
},
|
21
|
+
],
|
22
|
+
cursor: "",
|
23
|
+
},
|
24
|
+
query:
|
25
|
+
"query getRunsFeed($cursor: String, $filters: [Filters!]!) {\n runFeed(cursor: $cursor, filters: $filters) {\n cursor\n hasMore\n runs {\n runId\n createdAt\n completion {\n ...RunSummaryCompletion\n __typename\n }\n meta {\n ...RunSummaryMeta\n __typename\n }\n progress {\n ...RunProgress\n __typename\n }\n __typename\n }\n __typename\n }\n}\n\nfragment RunSummaryCompletion on RunCompletion {\n completed\n inactivityTimeoutMs\n __typename\n}\n\nfragment RunSummaryMeta on RunMeta {\n ciBuildId\n projectId\n commit {\n sha\n branch\n remoteOrigin\n message\n authorEmail\n authorName\n __typename\n }\n __typename\n}\n\nfragment RunProgress on RunProgress {\n updatedAt\n groups {\n groupId\n instances {\n ...RunGroupProgressInstances\n __typename\n }\n tests {\n ...RunGroupProgressTests\n __typename\n }\n __typename\n }\n __typename\n}\n\nfragment RunGroupProgressInstances on RunGroupProgressInstances {\n overall\n claimed\n complete\n failures\n passes\n __typename\n}\n\nfragment RunGroupProgressTests on RunGroupProgressTests {\n overall\n passes\n failures\n pending\n skipped\n flaky\n __typename\n}\n",
|
26
|
+
};
|
27
|
+
}
|
28
|
+
|
29
|
+
function getRunDetailsRequest(runId) {
|
30
|
+
return {
|
31
|
+
operationName: "getRun",
|
32
|
+
variables: {
|
33
|
+
runId: runId,
|
34
|
+
},
|
35
|
+
query:
|
36
|
+
"query getRun($runId: ID!) {\n run(id: $runId) {completion {\n ...RunSummaryCompletion\n __typename\n }\n meta {\n ...RunSummaryMeta\n __typename\n }\n specs {\n ...RunDetailSpec\n __typename\n }\n progress {\n ...RunProgress\n __typename\n }\n __typename\n }\n}\n\nfragment RunSummaryCompletion on RunCompletion {\n completed\n inactivityTimeoutMs\n __typename\n}\n\nfragment RunSummaryMeta on RunMeta {\n ciBuildId\n projectId\n commit {\n sha\n branch\n remoteOrigin\n message\n authorEmail\n authorName\n __typename\n }\n __typename\n}\n\nfragment RunDetailSpec on RunSpec {\n instanceId\n spec\n claimedAt\n machineId\n groupId\n results {\n error\n flaky\n stats {\n ...AllInstanceStats\n __typename\n }\n __typename\n }\n __typename\n}\n\nfragment AllInstanceStats on InstanceStats {\n suites\n tests\n pending\n passes\n failures\n skipped\n suites\n wallClockDuration\n wallClockStartedAt\n wallClockEndedAt\n __typename\n}\n\nfragment RunProgress on RunProgress {\n updatedAt\n groups {\n groupId\n instances {\n ...RunGroupProgressInstances\n __typename\n }\n tests {\n ...RunGroupProgressTests\n __typename\n }\n __typename\n }\n __typename\n}\n\nfragment RunGroupProgressInstances on RunGroupProgressInstances {\n overall\n claimed\n complete\n failures\n passes\n __typename\n}\n\nfragment RunGroupProgressTests on RunGroupProgressTests {\n overall\n passes\n failures\n pending\n skipped\n flaky\n __typename\n}\n",
|
37
|
+
};
|
38
|
+
}
|
39
|
+
|
40
|
+
function sleep(ms) {
|
41
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
42
|
+
}
|
43
|
+
|
44
|
+
async function getRuns(runName) {
|
45
|
+
const maxRetries = 1;
|
46
|
+
const retryDelay = 120000; // 2 mins
|
47
|
+
const projectId = getProjectId();
|
48
|
+
|
49
|
+
console.log(`Searching for run ${runName} using project ID: ${projectId}`);
|
50
|
+
|
51
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
52
|
+
try {
|
53
|
+
const response = await axios.post(graphqlUrl, getRunsRequest(), {
|
54
|
+
headers: { 'Content-Type': 'application/json' },
|
55
|
+
timeout: 30000
|
56
|
+
});
|
57
|
+
|
58
|
+
const { data } = response;
|
59
|
+
|
60
|
+
if (!data?.data?.runFeed?.runs) {
|
61
|
+
throw new Error(`Invalid API response structure: ${JSON.stringify(data)}`);
|
62
|
+
}
|
63
|
+
|
64
|
+
const runs = data.data.runFeed.runs;
|
65
|
+
console.log(`Found ${runs.length} runs`);
|
66
|
+
|
67
|
+
const run = runs.find(run => run.meta.ciBuildId === runName);
|
68
|
+
if (run) {
|
69
|
+
console.log(`Run ${runName} found with ID: ${run.runId}`);
|
70
|
+
return run;
|
71
|
+
}
|
72
|
+
|
73
|
+
if (attempt < maxRetries) {
|
74
|
+
console.log(`Run not found, retrying in ${retryDelay/1000} seconds...`);
|
75
|
+
await sleep(retryDelay);
|
76
|
+
}
|
77
|
+
} catch (error) {
|
78
|
+
console.error(`API error (attempt ${attempt + 1}/${maxRetries + 1}): ${error.message}`);
|
79
|
+
|
80
|
+
if (error.response) {
|
81
|
+
console.error(`Status: ${error.response.status}, Data:`, error.response.data);
|
82
|
+
}
|
83
|
+
|
84
|
+
if (attempt < maxRetries) {
|
85
|
+
console.log(`Retrying in ${retryDelay/1000} seconds...`);
|
86
|
+
await sleep(retryDelay);
|
87
|
+
} else {
|
88
|
+
throw new Error(`Failed after ${maxRetries + 1} attempts: ${error.message}`);
|
89
|
+
}
|
90
|
+
}
|
91
|
+
}
|
92
|
+
|
93
|
+
throw new Error(`Run ${runName} not found after ${maxRetries + 1} attempts`);
|
94
|
+
}
|
95
|
+
|
96
|
+
//Action starts here
|
97
|
+
export async function checkRunStatus(runName) {
|
98
|
+
try {
|
99
|
+
console.log(`Looking for run ${runName}`);
|
100
|
+
|
101
|
+
// Get run details
|
102
|
+
const run = await getRuns(runName);
|
103
|
+
const runId = run.runId;
|
104
|
+
console.log(`RunId found: ${runId}`);
|
105
|
+
|
106
|
+
// Wait for run to complete
|
107
|
+
await waitForRunCompletion(runId);
|
108
|
+
|
109
|
+
// Get final run details to check results
|
110
|
+
const runDetails = await getRunDetails(runId);
|
111
|
+
|
112
|
+
// Determine result
|
113
|
+
if (runDetails.data.run.completion.inactivityTimeoutMs >= sorryCypressTimeout) {
|
114
|
+
console.log(`Run ${runName} has timed out. Considering it as failed`);
|
115
|
+
return 1;
|
116
|
+
}
|
117
|
+
|
118
|
+
if (runDetails.data.run.progress.groups[0].tests.failures > 0) {
|
119
|
+
console.log(`Some tests in the run ${runName} have failed. Considering it as failed`);
|
120
|
+
return 1;
|
121
|
+
}
|
122
|
+
|
123
|
+
console.log(`No tests have failed in the run ${runName}. Considering it as successful`);
|
124
|
+
return 0;
|
125
|
+
} catch (error) {
|
126
|
+
console.error('Error checking run status:', error);
|
127
|
+
return 1;
|
128
|
+
}
|
129
|
+
}
|
130
|
+
|
131
|
+
async function getRunDetails(runId) {
|
132
|
+
try {
|
133
|
+
const response = await axios.post(graphqlUrl, getRunDetailsRequest(runId), {
|
134
|
+
headers: { 'Content-Type': 'application/json' },
|
135
|
+
timeout: 30000
|
136
|
+
});
|
137
|
+
|
138
|
+
const { data } = response;
|
139
|
+
|
140
|
+
if (!data?.data?.run) {
|
141
|
+
throw new Error(`Invalid run details response: ${JSON.stringify(data)}`);
|
142
|
+
}
|
143
|
+
|
144
|
+
return data;
|
145
|
+
} catch (error) {
|
146
|
+
console.error(`Failed to get run details: ${error.message}`);
|
147
|
+
if (error.response) {
|
148
|
+
console.error(`Status: ${error.response.status}, Data:`, error.response.data);
|
149
|
+
}
|
150
|
+
throw error;
|
151
|
+
}
|
152
|
+
}
|
153
|
+
|
154
|
+
async function waitForRunCompletion(runId) {
|
155
|
+
const checkInterval = 15000; // 15 seconds
|
156
|
+
const maxRetries = 5;
|
157
|
+
let isRunFinished = false;
|
158
|
+
let consecutiveErrors = 0;
|
159
|
+
|
160
|
+
console.log(`Waiting for run ${runId} to complete...`);
|
161
|
+
|
162
|
+
while (!isRunFinished) {
|
163
|
+
try {
|
164
|
+
const runDetails = await getRunDetails(runId);
|
165
|
+
const run = runDetails.data.run;
|
166
|
+
|
167
|
+
// Check if the run has timed out
|
168
|
+
if (run.completion.inactivityTimeoutMs >= sorryCypressTimeout) {
|
169
|
+
console.log('Run has timed out, marking as finished');
|
170
|
+
return;
|
171
|
+
}
|
172
|
+
|
173
|
+
// Check if run has progress data
|
174
|
+
if (run.progress?.groups?.length > 0) {
|
175
|
+
const group = run.progress.groups[0];
|
176
|
+
|
177
|
+
if (!group.instances) {
|
178
|
+
console.log('Missing instances in group, waiting...');
|
179
|
+
await sleep(checkInterval);
|
180
|
+
continue;
|
181
|
+
}
|
182
|
+
|
183
|
+
// Check if all instances are complete
|
184
|
+
isRunFinished = group.instances.overall === group.instances.complete;
|
185
|
+
console.log(`Run progress: ${group.instances.complete}/${group.instances.overall} complete`);
|
186
|
+
|
187
|
+
if (isRunFinished) {
|
188
|
+
console.log('Run is complete');
|
189
|
+
return;
|
190
|
+
}
|
191
|
+
} else {
|
192
|
+
console.log('Run has no progress groups yet, waiting...');
|
193
|
+
}
|
194
|
+
|
195
|
+
// Reset error counter on successful API call
|
196
|
+
consecutiveErrors = 0;
|
197
|
+
await sleep(checkInterval);
|
198
|
+
|
199
|
+
} catch (error) {
|
200
|
+
consecutiveErrors++;
|
201
|
+
console.error(`Error checking run status (error ${consecutiveErrors}/${maxRetries}): ${error.message}`);
|
202
|
+
|
203
|
+
if (consecutiveErrors >= maxRetries) {
|
204
|
+
throw new Error(`Maximum retries reached: ${error.message}`);
|
205
|
+
}
|
206
|
+
|
207
|
+
await sleep(checkInterval);
|
208
|
+
}
|
209
|
+
}
|
210
|
+
}
|
211
|
+
|
@@ -2,6 +2,7 @@ import { execSync } from "child_process";
|
|
2
2
|
import * as OS from "os";
|
3
3
|
import fetch from "node-fetch";
|
4
4
|
import { getS3Object } from "./awsHelper.mjs";
|
5
|
+
import { checkRunStatus } from "./run-status-check";
|
5
6
|
|
6
7
|
let ciBuildId;
|
7
8
|
let startTime;
|
@@ -239,9 +240,10 @@ export async function runSorryCypressLocalMigration() {
|
|
239
240
|
}
|
240
241
|
|
241
242
|
// Functions to execute cypress tests specific to Question Types
|
242
|
-
export function runSorryCypressQuestions() {
|
243
|
+
export async function runSorryCypressQuestions() {
|
243
244
|
process.env.CYPRESS_API_URL = "https://cypress-director.imaginelearning.tech/";
|
244
245
|
const user = OS.userInfo().username;
|
246
|
+
const isOtkv2 = process.env.OTK_VERSION === '2';
|
245
247
|
startTime = Math.round(Date.now() / 1000000);
|
246
248
|
ciBuildId = setCiBuildId(user, startTime);
|
247
249
|
|
@@ -265,6 +267,10 @@ export function runSorryCypressQuestions() {
|
|
265
267
|
console.log(`Running Command: ${command}`);
|
266
268
|
try {
|
267
269
|
execSync(command, {stdio: "inherit"});
|
270
|
+
if (isOtkv2) {
|
271
|
+
const status = await checkRunStatus(ciBuildId);
|
272
|
+
process.exit(status);
|
273
|
+
}
|
268
274
|
} catch (error) {
|
269
275
|
console.error("One or more tests failed to pass, OR an error occurred during run");
|
270
276
|
console.error("Cypress run error details:", {
|