froth-webdriverio-framework 3.0.88 → 3.0.90

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.
@@ -106,7 +106,7 @@ async function amend2Browserstack(annotationMessage, level) {
106
106
  try {
107
107
 
108
108
  console.log("Annotation message inside amend2Browserstack:" + annotationMessage)
109
- if (process.env.BROWSERSTACK)
109
+ if (process.env.PLATFORM === 'browserstack')
110
110
  await driver.execute('browserstack_executor: {"action": "annotate", "arguments": {"data":"' + annotationMessage + '","level": "' + level + '"}}');
111
111
 
112
112
  } catch (error) {
@@ -1,5 +1,5 @@
1
1
 
2
- const getLoginToken = require("../api/loginapi.js")
2
+ const getLoginToken = require("./loginapi.js")
3
3
  // Function to get data from the API using the Bearer token
4
4
 
5
5
  async function getExecuitonDetails(frothUrl, token, id) {
@@ -21,12 +21,15 @@ async function getExecuitonDetails(frothUrl, token, id) {
21
21
  if (response.ok) {
22
22
  const data = await response.json();
23
23
  // console.log(data)
24
- jsondata.automation_suite_id = data.automation_suite_id;
25
- jsondata.test_cycle_id = data.test_cycle_id;
26
- if (data.testcycle_type === "Android" || data.testcycle_type === "Ios") {
27
- jsondata.device_name = data.device_name
28
- jsondata.version = data.version
29
- }
24
+ jsondata.automation_suite_id = data.automation_suite_details.id;
25
+ jsondata.test_cycle_id = data.test_cycle_details.id;
26
+ jsondata.app_url = data.app_details ? data.app_details.app_url : null;
27
+ jsondata.browser_stack_local = data.capability_details ? data.capability_details.browser_stack_local: null;
28
+ jsondata.mediaurls =data.media_details ? data.media_details.map(media => media.media_url):null;
29
+
30
+ console.log("media urls :" + jsondata.mediaurls );
31
+
32
+
30
33
  // console.log("json data :" + JSON.stringify(jsondata));
31
34
 
32
35
  return jsondata;
@@ -53,7 +56,7 @@ async function getExecuitonDetails(frothUrl, token, id) {
53
56
 
54
57
  }
55
58
 
56
- async function getExecuitonScriptDetails(frothUrl, token, execution_id, script_id,script_platform) {
59
+ async function getExecuitonScriptDetails(frothUrl, token, execution_id, script_id, script_platform) {
57
60
  let id;
58
61
  const url = `${frothUrl}/api/execution-script-mapping/?execution_id=${execution_id}&automation_script_id=${script_id}&platform=${script_platform}`;
59
62
 
@@ -151,12 +154,12 @@ async function updateExecuitonDetails(frothUrl, token, id, resultdetails) {
151
154
 
152
155
  }
153
156
 
154
- async function updateScriptExecutionStatus(frothUrl, token, scriptid,script_platform, status) {
157
+ async function updateScriptExecutionStatus(frothUrl, token, scriptid, script_platform, status) {
155
158
 
156
159
  if (scriptid != 0) {
157
160
  try {
158
- console.log("script platform is "+script_platform)
159
- const id = await getExecuitonScriptDetails(frothUrl, token, BUFFER.getItem("FROTH_EXECUTION_ID"), scriptid,script_platform)
161
+ console.log("script platform is " + script_platform)
162
+ const id = await getExecuitonScriptDetails(frothUrl, token, BUFFER.getItem("FROTH_EXECUTION_ID"), scriptid, script_platform)
160
163
  console.log("ID is :" + id)
161
164
  const url = `${frothUrl}/api/script-status-percentage/${id}/`;
162
165
  const formData = new FormData();
@@ -182,7 +185,7 @@ async function updateScriptExecutionStatus(frothUrl, token, scriptid,script_plat
182
185
  // Call login function to obtain a new token
183
186
  const newToken = await getLoginToken(BUFFER.getItem("SERVICE_USER"), BUFFER.getItem("SERVICE_PASSWORD")); // You need to implement the login function
184
187
  // Retry the request with the new token
185
- return updateScriptExecutionStatus(frothUrl, newToken, scriptid,script_platform, status);
188
+ return updateScriptExecutionStatus(frothUrl, newToken, scriptid, script_platform, status);
186
189
  } else {
187
190
  const errorText = await response.text();
188
191
  console.error(`error in updating the status into DB ${response.status}`);
@@ -1,5 +1,5 @@
1
1
 
2
- const getLoginToken=require('./loginapi')
2
+ const getLoginToken = require('./loginapi')
3
3
  // Function to get data from the API using the Bearer token
4
4
  async function getSuiteDetails(frothUrl, token, id) {
5
5
  let jsondata = {};
@@ -18,24 +18,24 @@ async function getSuiteDetails(frothUrl, token, id) {
18
18
  });
19
19
  if (response.ok) {
20
20
  const data = await response.json();
21
- // console.log(data)
21
+ // console.log(data)
22
22
  jsondata.automation_suite_id = data.id == null ? 0 : data.id;
23
23
  jsondata.automation_suite_name = data.automation_suite_name == null ? "" : data.automation_suite_name;
24
24
  jsondata.test_data_id = data.test_data_id == null ? 0 : data.test_data_id;
25
25
  jsondata.browser_stack_urls = data.browser_stack_urls == null ? "" : data.browser_stack_urls;
26
- jsondata.script_details=data.script_details == null ? [] : data.script_details;
27
- // console.log("automation_script_id:" + JSON.stringify(jsondata.automation_script_id))
26
+ jsondata.script_details = data.script_details == null ? [] : data.script_details;
27
+ // console.log("automation_script_id:" + JSON.stringify(jsondata.automation_script_id))
28
28
  const automationScripts = jsondata.script_details.reduce((obj, item) => {
29
29
  obj[item.script_Id] = item.script_Id;
30
30
  BUFFER.setItem(item.scriptName, item.scriptId);
31
- BUFFER.setItem(item.scriptName+"_PLATFORM", item.platform);
31
+ BUFFER.setItem(item.scriptName + "_PLATFORM", item.platform);
32
32
 
33
- return obj;
33
+ return obj;
34
34
  }, {});
35
35
  jsondata.test_sequence = data.test_sequence;
36
- // console.log("automation_script_ details:" + JSON.stringify(BUFFER))
36
+ // console.log("automation_script_ details:" + JSON.stringify(BUFFER))
37
37
 
38
- // console.log("json data :" + JSON.stringify(jsondata));
38
+ // console.log("json data :" + JSON.stringify(jsondata));
39
39
 
40
40
  return jsondata;
41
41
 
@@ -48,7 +48,7 @@ async function getSuiteDetails(frothUrl, token, id) {
48
48
  else {
49
49
  const errorText = await response.text();
50
50
  console.error(`Data fetch failed response in getSuiteDetails: ${response.status}`);
51
- // throw new Error(`HTTP error! status: ${response.status}`);
51
+ // throw new Error(`HTTP error! status: ${response.status}`);
52
52
  }
53
53
 
54
54
 
@@ -1,5 +1,5 @@
1
1
 
2
- const getLoginToken = require('../api/loginapi.js');
2
+ const getLoginToken = require('./loginapi.js');
3
3
 
4
4
 
5
5
  // Function to get data from the API using the Bearer token
@@ -17,6 +17,7 @@ let swipetoFit = null;
17
17
  let swipeWithCoordinates = null;
18
18
 
19
19
  let clickIfVisible = null;
20
+ let doubleClick = null;
20
21
 
21
22
  let assertText = null;
22
23
  let randomtext = null;
@@ -37,15 +38,15 @@ let api = null;
37
38
 
38
39
  let selectDropDownValue = null;
39
40
 
40
- let acceptalert = null;
41
- let dismissalert = null;
41
+ let acceptAlert = null;
42
+ let dismissAlert = null;
42
43
 
43
44
  let generateJWT=null;
44
45
 
45
46
  if (process.env.LOCATION ==null || process.env.LOCATION == 'local') {
46
47
  basepath = ".";
47
48
  } else {
48
- basepath = "froth-webdriverio-framework/commonMethods";
49
+ basepath = "froth-webdriverio-framework/froth_common_actions";
49
50
  }
50
51
 
51
52
  scrollToEnd = require(basepath + "/scroll").scrollToEnd;
@@ -67,6 +68,7 @@ swipeWithCoordinates = require(basepath + '/swipe').swipewithcoordinates;
67
68
 
68
69
  clickIfVisible = require(basepath + "/click").clickIfVisible;
69
70
  clickByIdWithExecute = require(basepath + "/click").clickByIdWithExecute;
71
+ doubleClick= require(basepath + "/click").doubleclick;
70
72
 
71
73
  assertText = require(basepath + '/assert').assertText;
72
74
  assertAttributeValue = require(basepath + '/assert').assertAttributeValue;
@@ -88,8 +90,8 @@ validate = require(basepath + '/apicall').validate;
88
90
 
89
91
  selectDropDownValue = require(basepath + '/dropDown').select4mDropDownValue;
90
92
 
91
- acceptalert = require(basepath + '/alert.js').acceptAlert;
92
- dismissalert = require(basepath + '/alert.js').dismissAlert;
93
+ acceptAlert = require(basepath + '/alert.js').acceptalert;
94
+ dismissAlert = require(basepath + '/alert.js').dismissalert;
93
95
 
94
96
  generateJWT = require(basepath + '/jwt').generateJWTToken;
95
97
 
@@ -103,6 +105,7 @@ module.exports = {
103
105
  scrollRightToView,
104
106
  clickIfVisible,
105
107
  clickByIdWithExecute,
108
+ doubleClick,
106
109
  assertText,
107
110
  assertAttributeValue,
108
111
  randomtext,
@@ -120,8 +123,8 @@ module.exports = {
120
123
  api,
121
124
  validate,
122
125
  selectDropDownValue,
123
- acceptalert,
124
- dismissalert,
126
+ acceptAlert,
127
+ dismissAlert,
125
128
  swipeLeft,
126
129
  swipeRight,
127
130
  swipeDown,
@@ -1,4 +1,4 @@
1
- async function acceptAlert() {
1
+ async function acceptalert() {
2
2
 
3
3
  try {
4
4
  await browser.waitUntil(async () => {
@@ -14,7 +14,7 @@ async function acceptAlert() {
14
14
 
15
15
  }
16
16
 
17
- async function dismissAlert() {
17
+ async function dismissalert() {
18
18
  try {
19
19
  await browser.waitUntil(async () => {
20
20
  return await browser.isAlertOpen();
@@ -31,4 +31,4 @@ async function dismissAlert() {
31
31
 
32
32
  }
33
33
 
34
- module.exports = { acceptAlert, dismissAlert };
34
+ module.exports = { acceptalert, dismissalert };
@@ -1,4 +1,4 @@
1
- const amendToBrowserstack = require("../api/browsersatckSessionInfo").amend2Browserstack;
1
+ const amendToBrowserstack = require("../froth_api_calls/browsersatckSessionInfo").amend2Browserstack;
2
2
 
3
3
  async function callapi(method, api_url, queryParams, payloaddetails, authentication, headers, attachments) {
4
4
  let response;
@@ -88,8 +88,14 @@ async function validate(attribute_name, attribute, actionname, buffer, buffernam
88
88
  await validateAttributeData(attribute_name, attribute, buffer, buffername_value, datatype);
89
89
  } else if (actionname.toLowerCase() == "setbuffer") {
90
90
  BUFFER.setItem(buffername_value, attribute);
91
+ let annotationMessage = `The vlaue has been stored in the buffer : ${buffername_value}.`;
92
+ await amendToBrowserstack(annotationMessage, "info");
93
+
91
94
  } else if (actionname.toLowerCase() == "getbuffer") {
95
+ let annotationMessage = `The vlaue has been retrived from the buffer : ${buffername_value}.`;
96
+ await amendToBrowserstack(annotationMessage, "info");
92
97
  return BUFFER.getItem(buffername_value);
98
+
93
99
  }
94
100
  // } catch (e) {
95
101
  // console.error('Error in validate method:', e);
@@ -109,19 +115,25 @@ async function validateAttributeData(attribute_name, attribute, buffer, bufferna
109
115
  valueToVerify = Number(valueToVerify);
110
116
  } else if (datatype.toLowerCase() == "boolean") {
111
117
  valueToVerify = Boolean(valueToVerify);
118
+ }else if (datatype.toLowerCase() == "float") {
119
+ valueToVerify = parseFloat(valueToVerify);
120
+ }else if (datatype.toLowerCase() == "double") {
121
+ valueToVerify = parseFloat(valueToVerify);
122
+ }else if (datatype.toLowerCase() == "string") {
123
+ valueToVerify = valueToVerify.toString();
112
124
  }
113
125
 
114
126
  expect(attribute).toBe(valueToVerify, `${attribute_name} --> Expected value: ${valueToVerify}, but got: ${attribute}`);
115
127
  assertionStatus = true; // If assertion passes, set status to true
116
128
 
117
- console.log("verification succeeded.");
118
- let annotationMessage = `${attribute_name} - verification passed. Actual text: ${attribute}, Expected text: ${valueToVerify}.`;
129
+ console.log(`Attribute name : ${attribute_name} verification passed. Actual text: ${attribute}, Expected text: ${valueToVerify}.`);
130
+ let annotationMessage = `Attribute name : ${attribute_name} - verification passed. Actual text: ${attribute}, Expected text: ${valueToVerify}.`;
119
131
  await amendToBrowserstack(annotationMessage, "info");
120
132
 
121
133
  } catch (e) {
122
134
  console.error('Error in validateAttributeData:', e);
123
- console.log(`${attribute_name} verification failed. Expected text: ${valueToVerify}.`);
124
- let annotationMessage = `${attribute_name} - verification failed. Expected text: ${valueToVerify}.`;
135
+ console.log(`Attribute name : ${attribute_name} verification failed. Expected text: ${valueToVerify}. error: ${e.message}`);
136
+ let annotationMessage = `Attribute name : ${attribute_name} - verification failed. Expected text: ${valueToVerify}. error: ${e.message}`;
125
137
  await amendToBrowserstack(annotationMessage, "error");
126
138
 
127
139
  throw e;
@@ -20,7 +20,7 @@ async function clickIfVisible(elementSelector) {
20
20
  }
21
21
  }
22
22
 
23
- async function dobubleClick(elementSelector) {
23
+ async function doubleclick(elementSelector) {
24
24
  try {
25
25
  let isDisplayed;
26
26
  // Wait for the element to be visible
@@ -54,4 +54,4 @@ async function clickByIdWithExecute(elementid) {
54
54
  }
55
55
  }
56
56
 
57
- module.exports = { clickIfVisible, clickByIdWithExecute };
57
+ module.exports = { clickIfVisible, clickByIdWithExecute ,doubleclick};
@@ -47,18 +47,18 @@ function generateJWTToken(payload) {
47
47
  //console.log('Signed and encoded JWT', jwt)
48
48
 
49
49
 
50
- // function main() {
51
- // // JWT Payload
52
- // const payload = {
53
- // iss: "YTLC_TEST_AUTOMATION_APP",
54
- // iat: currentTimestamp, // Issued at
55
- // exp: currentTimestamp + 200, // Expiry time: 30 seconds from issuance
56
- // user_agent: {
57
- // id: "janga.reddy@ytl.com"
58
- // }
59
- // };
50
+ function main() {
51
+ // JWT Payload
52
+ const payload = {
53
+ iss: "YTLC_TEST_AUTOMATION_APP",
54
+ iat: currentTimestamp, // Issued at
55
+ exp: currentTimestamp + 200, // Expiry time: 30 seconds from issuance
56
+ user_agent: {
57
+ id: "janga.reddy@ytl.com"
58
+ }
59
+ };
60
60
 
61
- // console.log('JWT signed token:', generateJWTToken(payload));
62
- // }
63
- //main()
64
- module.exports = { generateJWTToken}
61
+ console.log('JWT signed token:', generateJWTToken(payload));
62
+ }
63
+ main()
64
+ //module.exports = { generateJWTToken}
@@ -2,10 +2,9 @@ const path = require('path');
2
2
  const { LocalStorage } = require('node-localstorage');
3
3
  global.BUFFER = new LocalStorage('./storage');
4
4
  const setAllDetails = require("./setallDatailinBuffer")
5
- const exeDetails = require("../api/getexecutionDetails")
6
- const getBSSessionDetails = require("../api/browsersatckSessionInfo").getBSSessionDetails;
5
+ const exeDetails = require("../froth_api_calls/getexecutionDetails")
6
+ const getBSSessionDetails = require("../froth_api_calls/browsersatckSessionInfo").getBSSessionDetails;
7
7
  const { fail } = require("assert");
8
- const { platform } = require("os");
9
8
  //const isBrowserStackEnabled = process.env.BROWSERSTACK;
10
9
  let starttime;
11
10
  let endtime;
@@ -20,7 +19,8 @@ const commonconfig = {
20
19
  // This code runs before the test suite starts
21
20
  await setAllDetails.setEnvVariables();
22
21
  await setAllDetails.setLoginToken();
23
- await setAllDetails.setExecutionDetails();
22
+ const getExeDetails = await setAllDetails.setExecutionDetails();
23
+
24
24
  // await setAllDetails.setIntegrationsDetails();
25
25
  await setAllDetails.setSuiteDetails();
26
26
  await setAllDetails.setTestDataDetails();
@@ -40,15 +40,17 @@ const commonconfig = {
40
40
 
41
41
  console.log("specdat:", specs);
42
42
  console.log("length:", specs.length);
43
- // console.log("capabilities:", capabilities);
44
- // capabilities.app = process.env.BROWSERSTACK_APP_PATH;
45
- // capabilities['browserstack.uploadMedia'] = process.env.MEDIA_FILES;
46
- // console.log("====>",capabilities)
47
- console.log(`Running tests on: ${capabilities.platformName} ${capabilities.browserName} ${capabilities.browserVersion}`);
48
43
 
44
+ if (process.env.PLATFORM === 'browserstack') {
45
+ /// console.log("capabilities:", capabilities);
46
+ capabilities.app = process.env.BROWSERSTACK_APP_PATH;
47
+ capabilities.browserstackLocal = process.env.BROWSERSTACK_LOCAL;
48
+ if (process.env.MEDIA_FILES)
49
+ capabilities['browserstack.uploadMedia'] = process.env.MEDIA_FILES;
50
+
51
+ console.log(`Running tests on after app,bslocal,mediafiles: ${capabilities}`);
52
+ }
49
53
 
50
- // console.log('specs:', specs);
51
- // console.log("Config:", config);
52
54
  },
53
55
  /**
54
56
  * Gets executed before the suite starts (in Mocha/Jasmine only).
@@ -60,9 +62,9 @@ const commonconfig = {
60
62
 
61
63
  starttime = new Date().getTime();
62
64
 
63
- if (platform === 'browserstack')
64
- await getBSSessionDetails(process.env.BS_SESSION_TYPE, process.env.BROWSERSTACK_USERNAME, process.env.BROWSERSTACK_ACCESS_KEY);
65
-
65
+ if (process.env.PLATFORM === 'browserstack')
66
+ await getBSSessionDetails(process.env.BS_SESSION_TYPE, process.env.BROWSERSTACK_USERNAME, process.env.BROWSERSTACK_ACCESS_KEY);
67
+
66
68
  const resultdetails = {};
67
69
  exeDetails.updateExecuitonDetails(BUFFER.getItem("ORGANISATION_DOMAIN_URL"), BUFFER.getItem("FROTH_LOGIN_TOKEN"), BUFFER.getItem("FROTH_EXECUTION_ID"), resultdetails)
68
70
 
@@ -167,7 +169,7 @@ const commonconfig = {
167
169
  let totalDuration = endtime - starttime;
168
170
  console.log("====> Total Duration in after session based on start time and end time:" + totalDuration);
169
171
 
170
- if (platform === 'browserstack')
172
+ if (process.env.PLATFORM === 'browserstack')
171
173
  await getBSSessionDetails(process.env.BS_SESSION_TYPE, process.env.BROWSERSTACK_USERNAME, process.env.BROWSERSTACK_ACCESS_KEY);
172
174
 
173
175
  const resultdetails = {}
@@ -179,39 +181,39 @@ const commonconfig = {
179
181
  BUFFER.clear();
180
182
 
181
183
 
182
- // Perform any cleanup or post-test actions here
183
- },
184
+ // Perform any cleanup or post-test actions here
185
+ },
184
186
 
185
- onComplete: async function (exitCode, config, capabilities, results) {
187
+ onComplete: async function (exitCode, config, capabilities, results) {
186
188
 
187
- console.log('====> This is the onComplete hook', results);
189
+ console.log('====> This is the onComplete hook', results);
188
190
 
189
- console.log('====> Test Results Summary ');
190
- console.log('----------------------------');
191
+ console.log('====> Test Results Summary ');
192
+ console.log('----------------------------');
191
193
 
192
- console.log('Total Tests:', results.total);
193
- console.log('Passed:', results.passed);
194
- console.log('Failed:', results.failed);
195
- console.log('Skipped:', results.skipped);
196
- console.log('Execution Time:', results.duration);
197
- console.log('Exit Code:', exitCode);
198
- console.log('====> All tests are done, exiting the browser session.');
194
+ console.log('Total Tests:', results.total);
195
+ console.log('Passed:', results.passed);
196
+ console.log('Failed:', results.failed);
197
+ console.log('Skipped:', results.skipped);
198
+ console.log('Execution Time:', results.duration);
199
+ console.log('Exit Code:', exitCode);
200
+ console.log('====> All tests are done, exiting the browser session.');
199
201
 
200
- }
202
+ }
201
203
 
202
- };
204
+ };
203
205
 
204
- async function secondsToTime(secs) {
205
- let hours = Math.floor(secs / 3600);
206
- let minutes = Math.floor((secs % 3600) / 60);
207
- let seconds = secs % 60;
206
+ async function secondsToTime(secs) {
207
+ let hours = Math.floor(secs / 3600);
208
+ let minutes = Math.floor((secs % 3600) / 60);
209
+ let seconds = secs % 60;
208
210
 
209
- // Adding leading zeros if the value is less than 10
210
- if (hours < 10) hours = '0' + hours;
211
- if (minutes < 10) minutes = '0' + minutes;
212
- if (seconds < 10) seconds = '0' + seconds;
213
- console.log("Time:" + hours + ':' + minutes + ':' + seconds);
214
- return hours + ':' + minutes + ':' + seconds;
211
+ // Adding leading zeros if the value is less than 10
212
+ if (hours < 10) hours = '0' + hours;
213
+ if (minutes < 10) minutes = '0' + minutes;
214
+ if (seconds < 10) seconds = '0' + seconds;
215
+ console.log("Time:" + hours + ':' + minutes + ':' + seconds);
216
+ return hours + ':' + minutes + ':' + seconds;
215
217
  }
216
218
 
217
219
  async function convertTimetoHHMMSS(time) {
@@ -1,8 +1,8 @@
1
- const getLoginToken = require("../api/loginapi");
2
- const exeDetails = require("../api/getexecutionDetails")
3
- //const getintegrationdetails = require("../api/getintegrationDetails");
4
- const getSuiteDetails = require("../api/getsuiteDetails");
5
- const getDataById = require("../api/readTestdata");
1
+ const getLoginToken = require("../froth_api_calls/loginapi");
2
+ const exeDetails = require("../froth_api_calls/getexecutionDetails")
3
+ //const getintegrationdetails = require("../froth_api_calls/getintegrationDetails");
4
+ const getSuiteDetails = require("../froth_api_calls/getsuiteDetails");
5
+ const getDataById = require("../froth_api_calls/readTestdata");
6
6
 
7
7
 
8
8
  async function generateBuildNumber() {
@@ -64,6 +64,9 @@ async function setExecutionDetails() {
64
64
  try {
65
65
  const getExeDetails = await exeDetails.getExecuitonDetails(BUFFER.getItem("ORGANISATION_DOMAIN_URL"), BUFFER.getItem("FROTH_LOGIN_TOKEN"), BUFFER.getItem("FROTH_EXECUTION_ID"));
66
66
  BUFFER.setItem("AUTOMATION_SUITE_ID", getExeDetails.automation_suite_id);
67
+ BUFFER.setItem("BROWSERSTACK_LOCAL", getExeDetails.browser_stack_local);
68
+ BUFFER.setItem("BROWSERSTACK_APP_PATH", getExeDetails.app_url);
69
+ BUFFER.setItem("MEDIA_FILES", getExeDetails.mediaurls);
67
70
 
68
71
  } catch (error) {
69
72
  // console.error('Error in main function:', error);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "froth-webdriverio-framework",
3
- "version": "3.0.88",
3
+ "version": "3.0.90",
4
4
  "readme": "WebdriverIO Integration",
5
5
  "description": "WebdriverIO and BrowserStack App Automate",
6
6
  "license": "MIT",
File without changes
File without changes