itemengine-cypress-automation 1.0.519-dependabot-npm-and-yarn-multi-c7c3a225fc-be735c0.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 CHANGED
@@ -28,7 +28,6 @@ RUN chmod +x ./deploy/resourcesAndToolsQuestion/run.sh
28
28
  RUN chmod +x ./deploy/audioResponseQuestion/run.sh
29
29
  RUN chmod +x ./deploy/dataApi/run.sh
30
30
  RUN chmod +x ./deploy/feedbackScaleQuestion/run.sh
31
- RUN chmod +x ./deploy/test/run.sh
32
31
 
33
32
  RUN npm ci
34
33
 
@@ -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
@@ -11,6 +11,7 @@ otk:
11
11
  linuxDistribution: alpine
12
12
  language: node
13
13
  languageVersion: "20"
14
+ analysis: false
14
15
  deployables:
15
16
  - ./deploy/audioResponseQuestion/service.yaml
16
17
  # - ./deploy/DNDIntoCategoriesQuestion/service.yaml
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "itemengine-cypress-automation",
3
- "version": "1.0.519-dependabot-npm-and-yarn-multi-c7c3a225fc-be735c0.0",
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": "^15.2.0",
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:", {