@appliqation/automation-sdk 2.1.1 → 2.1.3

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/README.md CHANGED
@@ -105,7 +105,8 @@ const appliqationConfig = {
105
105
  batchSubmit: true, // Batch results for efficiency
106
106
  batchSize: 50, // Results per batch
107
107
  logOrphans: true, // Log tests without UUID mappings
108
- logLevel: 'INFO' // INFO, DEBUG, ERROR
108
+ logLevel: 'INFO', // INFO, DEBUG, ERROR
109
+ rejectUnauthorized: false // Set to false for self-signed certificates in dev
109
110
  };
110
111
 
111
112
  module.exports = defineConfig({
@@ -655,6 +656,31 @@ npm install dotenv
655
656
 
656
657
  ---
657
658
 
659
+ #### ❌ Error: "unable to verify the first certificate" or SSL errors
660
+
661
+ **Cause:** Using self-signed SSL certificates in development environment
662
+
663
+ **Fix:**
664
+
665
+ Add `rejectUnauthorized: false` to your SDK configuration in `playwright.config.js`:
666
+
667
+ ```javascript
668
+ const appliqationConfig = {
669
+ baseUrl: process.env.APPLIQATION_BASE_URL,
670
+ apiKey: process.env.APPLIQATION_API_KEY,
671
+ projectKey: process.env.APPLIQATION_PROJECT_KEY,
672
+ environment: process.env.APPLIQATION_ENVIRONMENT,
673
+ title: process.env.APPLIQATION_RUN_TITLE,
674
+
675
+ // Add this for self-signed certificates
676
+ rejectUnauthorized: false // ⚠️ Only use in development!
677
+ };
678
+ ```
679
+
680
+ **⚠️ Security Note:** Only use `rejectUnauthorized: false` in development environments with self-signed certificates. In production with valid SSL certificates, remove this setting or set it to `true`.
681
+
682
+ ---
683
+
658
684
  #### ❌ Results not appearing in portal
659
685
 
660
686
  **Possible causes:**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@appliqation/automation-sdk",
3
- "version": "2.1.1",
3
+ "version": "2.1.3",
4
4
  "description": "Appliqation Automation SDK with API key authentication, custom run titles, and framework-specific reporters",
5
5
  "main": "src/index.js",
6
6
  "types": "src/index.d.ts",
@@ -13,6 +13,14 @@
13
13
  "require": "./src/reporters/playwright/index.js",
14
14
  "import": "./src/reporters/playwright/index.js"
15
15
  },
16
+ "./playwright/global-setup": {
17
+ "require": "./src/playwright/global-setup.js",
18
+ "import": "./src/playwright/global-setup.js"
19
+ },
20
+ "./playwright/fixture": {
21
+ "require": "./src/playwright/fixture.js",
22
+ "import": "./src/playwright/fixture.js"
23
+ },
16
24
  "./cypress": {
17
25
  "require": "./src/reporters/cypress/index.js",
18
26
  "import": "./src/reporters/cypress/index.js"
@@ -140,12 +140,13 @@ function extractSDKConfig(config) {
140
140
  * Get JWT token from Appliqation API
141
141
  *
142
142
  * @param {Object} sdkConfig - SDK configuration
143
- * @returns {Promise<Object>} JWT data { jwt_token, run_id }
143
+ * @returns {Promise<Object>} JWT data { jwt_token, run_id, user_id, project_id }
144
144
  */
145
145
  async function getJWTToken(sdkConfig) {
146
- const endpoint = `${sdkConfig.baseUrl.replace(/\/$/, '')}/api/automation/run/create`;
146
+ // STEP 1: Create automation run
147
+ const createRunEndpoint = `${sdkConfig.baseUrl.replace(/\/$/, '')}/api/automation/run/create`;
147
148
 
148
- const payload = {
149
+ const runPayload = {
149
150
  project_key: sdkConfig.projectKey,
150
151
  scenario_id: sdkConfig.scenarioId || 0,
151
152
  environment: sdkConfig.environment,
@@ -156,7 +157,7 @@ async function getJWTToken(sdkConfig) {
156
157
  };
157
158
 
158
159
  try {
159
- const response = await axios.post(endpoint, payload, {
160
+ const runResponse = await axios.post(createRunEndpoint, runPayload, {
160
161
  headers: {
161
162
  'Content-Type': 'application/json',
162
163
  'X-API-Key': sdkConfig.apiKey,
@@ -167,14 +168,39 @@ async function getJWTToken(sdkConfig) {
167
168
  validateStatus: (status) => status < 500,
168
169
  });
169
170
 
170
- if (response.status !== 200 && response.status !== 201) {
171
- throw new Error(`API returned status ${response.status}: ${response.data?.message || 'Unknown error'}`);
171
+ if (runResponse.status !== 200 && runResponse.status !== 201) {
172
+ throw new Error(`Run creation failed: ${runResponse.status} - ${runResponse.data?.message || 'Unknown error'}`);
173
+ }
174
+
175
+ const runId = runResponse.data.run_id;
176
+
177
+ // STEP 2: Get browser session JWT token
178
+ const jwtEndpoint = `${sdkConfig.baseUrl.replace(/\/$/, '')}/api/auth/jwt/browser`;
179
+
180
+ const jwtPayload = {
181
+ api_key: sdkConfig.apiKey
182
+ };
183
+
184
+ const jwtResponse = await axios.post(jwtEndpoint, jwtPayload, {
185
+ headers: {
186
+ 'Content-Type': 'application/json',
187
+ },
188
+ httpsAgent: new https.Agent({
189
+ rejectUnauthorized: false, // Allow self-signed certs in dev
190
+ }),
191
+ validateStatus: (status) => status < 500,
192
+ });
193
+
194
+ if (jwtResponse.status !== 200) {
195
+ throw new Error(`JWT generation failed: ${jwtResponse.status} - ${jwtResponse.data?.message || 'Unknown error'}`);
172
196
  }
173
197
 
174
198
  return {
175
- jwt_token: response.data.jwt_token,
176
- run_id: response.data.run_id,
177
- metadata: response.data.metadata,
199
+ jwt_token: jwtResponse.data.jwt_token,
200
+ run_id: runId,
201
+ user_id: jwtResponse.data.user_id,
202
+ project_id: jwtResponse.data.project_id,
203
+ expires_in: jwtResponse.data.expires_in,
178
204
  };
179
205
 
180
206
  } catch (error) {
@@ -197,25 +223,40 @@ async function setupBrowserWithJWT(sdkConfig, jwtToken) {
197
223
  headless: true,
198
224
  });
199
225
 
200
- const context = await browser.newContext({
201
- ignoreHTTPSErrors: true, // Allow self-signed certs in dev
202
- });
226
+ try {
227
+ // Extract domain from baseUrl for cookie
228
+ const baseUrl = sdkConfig.baseUrl.replace(/\/$/, '');
229
+ const urlObj = new URL(baseUrl);
230
+ const domain = urlObj.hostname;
231
+
232
+ // Create context with JWT cookie BEFORE navigating
233
+ const context = await browser.newContext({
234
+ ignoreHTTPSErrors: true, // Allow self-signed certs in dev
235
+ });
203
236
 
204
- const page = await context.newPage();
237
+ // Set JWT cookie
238
+ await context.addCookies([{
239
+ name: 'appliqation_jwt',
240
+ value: jwtToken,
241
+ domain: domain,
242
+ path: '/',
243
+ httpOnly: true,
244
+ secure: baseUrl.startsWith('https'),
245
+ sameSite: 'Lax'
246
+ }]);
205
247
 
206
- try {
207
- // Navigate to app with JWT token in query parameter
208
- const appUrl = sdkConfig.appUrl.replace(/\/$/, '');
209
- const separator = appUrl.includes('?') ? '&' : '?';
210
- const urlWithToken = `${appUrl}${separator}qonsole_token=${encodeURIComponent(jwtToken)}`;
248
+ console.log(` ✓ JWT cookie set for domain: ${domain}`);
211
249
 
212
- console.log(` Navigating to: ${appUrl}...`);
213
- await page.goto(urlWithToken, {
250
+ const page = await context.newPage();
251
+
252
+ // Navigate to app (no query parameter needed)
253
+ console.log(` Navigating to: ${baseUrl}...`);
254
+ await page.goto(baseUrl, {
214
255
  waitUntil: 'networkidle',
215
256
  timeout: 30000,
216
257
  });
217
258
 
218
- // Wait a bit for session to be established
259
+ // Wait for authentication to be processed
219
260
  await page.waitForTimeout(2000);
220
261
 
221
262
  // Verify authentication worked
@@ -224,14 +265,16 @@ async function setupBrowserWithJWT(sdkConfig, jwtToken) {
224
265
  throw new Error('JWT authentication failed - redirected to login page');
225
266
  }
226
267
 
227
- // Save authenticated state
268
+ console.log(' ✓ Browser authenticated successfully');
269
+
270
+ // Save authenticated state with cookie
228
271
  const authDir = path.resolve('.auth');
229
272
  if (!fs.existsSync(authDir)) {
230
273
  fs.mkdirSync(authDir, { recursive: true });
231
274
  }
232
275
 
233
276
  await context.storageState({ path: '.auth/jwt.json' });
234
- console.log(' ✓ Authenticated state saved');
277
+ console.log(' ✓ Authenticated state saved to .auth/jwt.json');
235
278
 
236
279
  } catch (error) {
237
280
  throw new Error(`Browser setup failed: ${error.message}`);