@appliqation/automation-sdk 2.3.1 → 2.4.0

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
@@ -3,6 +3,7 @@
3
3
  A powerful SDK for integrating Playwright test results with the Appliqation test management portal.
4
4
 
5
5
  **What it does:**
6
+ - ✅ **Auto-configuration** - Configure with just an API key (NEW!)
6
7
  - ✅ Automatically creates test runs in Appliqation
7
8
  - ✅ Handles browser authentication with JWT tokens
8
9
  - ✅ Reports test results (passed/failed/skipped) to your portal
@@ -41,6 +42,19 @@ Before you begin, ensure you have:
41
42
 
42
43
  Follow these steps in order to integrate the SDK with your Playwright tests.
43
44
 
45
+ > **🎉 NEW: Simplified Configuration**
46
+ > You now only need **one configuration value** to get started! Just provide your API key and the SDK automatically fetches your project ID and environment. This reduces setup from 3 required values to just 1.
47
+ >
48
+ > ```bash
49
+ > # Before: 3 required values
50
+ > APPLIQATION_API_KEY=...
51
+ > APPLIQATION_PROJECT_KEY=... # ❌ No longer required
52
+ > APPLIQATION_ENVIRONMENT=... # ❌ No longer required
53
+ >
54
+ > # After: 1 required value
55
+ > APPLIQATION_API_KEY=... # ✅ That's it!
56
+ > ```
57
+
44
58
  **📌 Important:** Appliqation reporting is **opt-in**. You must either set `APPQ_ENABLE=1` environment variable or add `-- --appq` flag to your test command to send results to Appliqation. Without enabling reporting, tests run normally but results are not reported.
45
59
 
46
60
  ### Step 1: Install the SDK
@@ -59,20 +73,25 @@ npm install @appliqation/automation-sdk dotenv
59
73
 
60
74
  Create a `.env` file in your project root with your Appliqation credentials:
61
75
 
62
- **File:** `.env`
76
+ **File:** `.env` (Simplified - Recommended)
63
77
  ```bash
64
- # IMPORTANT: No spaces around = signs, no trailing slashes on URLs
78
+ # 🎉 NEW: Auto-Configuration - Only API key required!
79
+ # The SDK automatically fetches project ID and environment from your API key
65
80
 
66
81
  APPLIQATION_API_KEY=appq_live_xxxxxxxxxxxxxxxxxxxx
67
- APPLIQATION_PROJECT_KEY=your-project-key-here
68
82
  TEST_APP_URL=https://www.example.com # App under test (Playwright baseURL)
69
83
  ```
70
84
 
71
- **How to get these values:**
72
- - `APPLIQATION_API_KEY` - Found in your project settings
73
- - `APPLIQATION_PROJECT_KEY` - Found in your project settings
74
- - `TEST_APP_URL` - The site you’re testing (e.g., https://www.amazon.in). Used as Playwright `baseURL`.
75
- -
85
+ **That's it!** The SDK will automatically:
86
+ - Fetch your project ID from the API key
87
+ - Detect available environments
88
+ - Use the default environment
89
+
90
+ **How to get your API key:**
91
+ - Go to your Appliqation project settings
92
+ - Navigate to Settings > API Keys
93
+ - Generate a new API key
94
+ - Copy the API key (starts with `appq_live_`)
76
95
 
77
96
  **⚠️ Add .env to .gitignore** to keep credentials secret:
78
97
  ```bash
@@ -81,20 +100,50 @@ echo ".env" >> .gitignore
81
100
 
82
101
  ---
83
102
 
103
+ <details>
104
+ <summary><strong>Advanced: Manual Configuration (Optional)</strong></summary>
105
+
106
+ If you prefer to specify project ID and environment manually (or need backward compatibility), you can use the traditional configuration:
107
+
108
+ ```bash
109
+ # Traditional configuration - Still supported!
110
+ APPLIQATION_API_KEY=appq_live_xxxxxxxxxxxxxxxxxxxx
111
+ APPLIQATION_PROJECT_KEY=1162 # Optional: Auto-fetched if not provided
112
+ APPLIQATION_ENVIRONMENT=Production # Optional: Uses default if not provided
113
+ TEST_APP_URL=https://www.example.com
114
+ ```
115
+
116
+ **When to use manual configuration:**
117
+ - You want to override the auto-detected environment
118
+ - You're testing the SDK in development
119
+ - You have specific environment requirements
120
+ - Backward compatibility with existing setups
121
+
122
+ **Benefits of auto-configuration:**
123
+ - Simpler setup (1 value instead of 3)
124
+ - Less configuration errors
125
+ - Automatic environment validation
126
+ - Easy to get started for new users
127
+
128
+ </details>
129
+
130
+ ---
131
+
84
132
  ### Step 3: Update playwright.config.js
85
133
 
86
134
  Update your Playwright configuration to use the SDK's built-in features:
87
135
 
88
- **File:** `playwright.config.js`
136
+ **File:** `playwright.config.js` (Simplified)
89
137
 
90
138
  ```javascript
91
139
  const { defineConfig } = require('@playwright/test');
92
140
  require('dotenv').config(); // Load .env variables
93
141
 
94
- // SDK configuration
142
+ // SDK configuration - Auto-configuration enabled!
95
143
  const appliqationConfig = {
96
144
  apiKey: process.env.APPLIQATION_API_KEY,
97
- projectKey: process.env.APPLIQATION_PROJECT_KEY,
145
+ // projectKey: Auto-fetched from API key! ✨
146
+ // environment: Auto-detected default environment! ✨
98
147
 
99
148
  // Optional settings
100
149
  autoCreateRun: true, // Automatically create run on test start
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@appliqation/automation-sdk",
3
- "version": "2.3.1",
3
+ "version": "2.4.0",
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",
@@ -134,21 +134,165 @@ class AppliqationClient {
134
134
  // Track current run context
135
135
  this.currentRun = null;
136
136
 
137
+ // Auto-configuration state
138
+ this._autoConfigured = false;
139
+ this._projectInfo = null;
140
+ this._autoConfigPromise = null; // Prevents concurrent auto-config calls
141
+
137
142
  // Show baseUrl only in DEBUG mode
138
143
  const meta = {
139
- authMode: this.config.apiKey ? 'api_key' : 'csrf'
144
+ authMode: this.config.apiKey ? 'api_key' : 'csrf',
145
+ autoConfigEnabled: !this.config.projectKey // Will auto-fetch if projectKey not provided
140
146
  };
141
147
  logger.info('Appliqation client initialized', meta);
142
148
  logger.debug('Client configuration', { baseUrl: this.config.baseUrl });
143
149
  }
144
150
 
151
+ /**
152
+ * Ensure project configuration is loaded
153
+ * Automatically fetches project metadata from API key if projectKey not provided.
154
+ * This method is idempotent and can be called multiple times safely.
155
+ *
156
+ * @private
157
+ * @returns {Promise<void>}
158
+ * @throws {Error} If auto-configuration fails
159
+ */
160
+ async ensureProjectConfig() {
161
+ // If projectKey provided manually, no need to fetch
162
+ if (this.config.projectKey) {
163
+ return;
164
+ }
165
+
166
+ // If already auto-configured, skip
167
+ if (this._autoConfigured) {
168
+ return;
169
+ }
170
+
171
+ // If auto-config is in progress, wait for it
172
+ if (this._autoConfigPromise) {
173
+ return this._autoConfigPromise;
174
+ }
175
+
176
+ // Start auto-configuration
177
+ this._autoConfigPromise = this._performAutoConfig();
178
+
179
+ try {
180
+ await this._autoConfigPromise;
181
+ } finally {
182
+ this._autoConfigPromise = null;
183
+ }
184
+ }
185
+
186
+ /**
187
+ * Perform auto-configuration by fetching project info
188
+ * @private
189
+ * @returns {Promise<void>}
190
+ */
191
+ async _performAutoConfig() {
192
+ logger.info('Auto-fetching project configuration from API key...');
193
+
194
+ try {
195
+ this._projectInfo = await this.http.getProjectInfo();
196
+
197
+ // Validate response structure
198
+ if (!this._projectInfo || typeof this._projectInfo !== 'object') {
199
+ throw new Error(
200
+ `Invalid response format: expected object, got ${typeof this._projectInfo}`
201
+ );
202
+ }
203
+
204
+ if (!this._projectInfo.project_id && this._projectInfo.project_id !== 0) {
205
+ throw new Error(
206
+ `Invalid response: missing project_id field in API response`
207
+ );
208
+ }
209
+
210
+ this._autoConfigured = true;
211
+
212
+ // Update config with fetched project_id
213
+ this.config.projectKey = this._projectInfo.project_id.toString();
214
+
215
+ logger.info('Auto-configuration successful', {
216
+ project_id: this._projectInfo.project_id,
217
+ project_title: this._projectInfo.project_title,
218
+ environments: this._projectInfo.environments,
219
+ default_environment: this._projectInfo.default_environment
220
+ });
221
+
222
+ // Log warning if no environments configured
223
+ if (!this._projectInfo.has_environments_configured) {
224
+ logger.warn('Project has no environments configured. Using default environment "Local".', {
225
+ project_id: this._projectInfo.project_id,
226
+ action_required: 'Configure environments in project settings for better environment validation'
227
+ });
228
+ }
229
+ } catch (error) {
230
+ logger.error('Auto-configuration failed', {
231
+ error: error.message
232
+ });
233
+
234
+ throw new Error(
235
+ `Failed to auto-configure project from API key: ${error.message}\n\n` +
236
+ 'Possible solutions:\n' +
237
+ '1. Verify your API key is valid and not expired\n' +
238
+ '2. Ensure your API key is associated with a valid project\n' +
239
+ '3. Check network connectivity to Appliqation instance\n' +
240
+ '4. Provide projectKey manually in configuration as fallback:\n' +
241
+ ' { projectKey: "your-project-id" }'
242
+ );
243
+ }
244
+ }
245
+
246
+ /**
247
+ * Get available environments for the project
248
+ * Automatically triggers project info fetch if not already loaded.
249
+ *
250
+ * @returns {Promise<Array<string>>} List of environment names
251
+ * @example
252
+ * const environments = await client.getAvailableEnvironments();
253
+ * console.log(environments); // ['Development', 'Staging', 'Production']
254
+ */
255
+ async getAvailableEnvironments() {
256
+ await this.ensureProjectConfig();
257
+ return this._projectInfo?.environments || [];
258
+ }
259
+
260
+ /**
261
+ * Get default environment for the project
262
+ * Automatically triggers project info fetch if not already loaded.
263
+ *
264
+ * @returns {Promise<string>} Default environment name
265
+ * @example
266
+ * const defaultEnv = await client.getDefaultEnvironment();
267
+ * console.log(defaultEnv); // 'Development'
268
+ */
269
+ async getDefaultEnvironment() {
270
+ await this.ensureProjectConfig();
271
+ return this._projectInfo?.default_environment || 'Local';
272
+ }
273
+
274
+ /**
275
+ * Get cached project information
276
+ * Returns null if auto-configuration hasn't been triggered yet.
277
+ *
278
+ * @returns {Object|null} Project metadata or null
279
+ * @property {number} project_id - Project ID
280
+ * @property {string} project_title - Project name
281
+ * @property {Array<string>} environments - Available environments
282
+ * @property {string} default_environment - Default environment
283
+ * @property {boolean} has_environments_configured - Whether environments exist
284
+ */
285
+ getProjectInfo() {
286
+ return this._projectInfo;
287
+ }
288
+
145
289
  /**
146
290
  * Create a new test run matrix
147
291
  * @param {Object} options - Run configuration
148
292
  * @param {number} options.scenarioId - Scenario node ID
149
293
  * @param {number} options.testSetId - Test Set node ID (alternative to scenarioId)
150
294
  * @param {string} options.type - 'scenario' or 'testset'
151
- * @param {string} [options.environment='Local'] - Environment name
295
+ * @param {string} [options.environment='Local'] - Environment name (auto-detected if not provided)
152
296
  * @param {string[]} [options.browsers=['Chrome']] - Array of browser names
153
297
  * @param {string} [options.device] - Device type (Desktop, Mobile, Tablet)
154
298
  * @param {string} [options.os] - Operating system
@@ -157,6 +301,18 @@ class AppliqationClient {
157
301
  */
158
302
  async createRun(options) {
159
303
  try {
304
+ // Ensure project config is loaded (auto-fetch if needed)
305
+ await this.ensureProjectConfig();
306
+
307
+ // If environment not provided, use auto-detected default
308
+ if (!options.environment && this._projectInfo) {
309
+ options.environment = this._projectInfo.default_environment;
310
+ logger.info('Using auto-detected default environment', {
311
+ environment: options.environment,
312
+ source: 'project_config'
313
+ });
314
+ }
315
+
160
316
  logger.info('Creating run matrix...', options);
161
317
 
162
318
  const run = await this.runMatrix.create(options);
@@ -504,23 +660,7 @@ class AppliqationClient {
504
660
  );
505
661
  }
506
662
 
507
- if (!config.projectKey) {
508
- throw new Error(
509
- 'projectKey is required.\n' +
510
- 'Please set the APPLIQATION_PROJECT_KEY environment variable or provide projectKey in configuration:\n' +
511
- ' APPLIQATION_PROJECT_KEY=your-project-key\n' +
512
- 'Or in code:\n' +
513
- ' { projectKey: "your-project-key" }\n' +
514
- '\n' +
515
- 'You can find your project key in the Appliqation dashboard under Project Settings.'
516
- );
517
- }
518
-
519
- // Note: Both base64-encoded project keys AND numeric project IDs are now supported
520
- // Numeric IDs are a temporary workaround for duplicate project key issues
521
- // The backend will validate the project key format and access permissions
522
-
523
- // Must have either API key or username/password
663
+ // Must have either API key or username/password for authentication
524
664
  if (!config.apiKey && (!config.username || !config.password)) {
525
665
  throw new Error(
526
666
  'Authentication credentials are required.\n' +
@@ -535,6 +675,27 @@ class AppliqationClient {
535
675
  );
536
676
  }
537
677
 
678
+ // projectKey is now optional when using API key authentication
679
+ // If not provided, it will be auto-fetched from the API key's associated project
680
+ if (!config.projectKey && !config.apiKey) {
681
+ throw new Error(
682
+ 'projectKey is required when not using API key authentication.\n' +
683
+ 'Please set the APPLIQATION_PROJECT_KEY environment variable or provide projectKey in configuration:\n' +
684
+ ' APPLIQATION_PROJECT_KEY=your-project-key\n' +
685
+ 'Or in code:\n' +
686
+ ' { projectKey: "your-project-key" }\n' +
687
+ '\n' +
688
+ 'Alternatively, use API key authentication (recommended) and projectKey will be auto-fetched:\n' +
689
+ ' APPLIQATION_API_KEY=appq_live_xxxxxxxxxxxx\n' +
690
+ '\n' +
691
+ 'You can find your project key in the Appliqation dashboard under Project Settings.'
692
+ );
693
+ }
694
+
695
+ // Note: Both base64-encoded project keys AND numeric project IDs are supported
696
+ // Numeric IDs are used when auto-fetched from API key
697
+ // The backend validates project access permissions
698
+
538
699
  // Validate URL format
539
700
  try {
540
701
  new URL(config.baseUrl);
@@ -306,6 +306,68 @@ class HttpClient {
306
306
  }
307
307
  }
308
308
 
309
+ /**
310
+ * Fetch project information from API key
311
+ * Enables SDK auto-configuration where only API key is required.
312
+ * Returns project metadata including ID, title, and configured environments.
313
+ *
314
+ * @returns {Promise<Object>} Project metadata
315
+ * @property {boolean} success - Operation success status
316
+ * @property {number} project_id - Numeric project ID
317
+ * @property {number} project_nid - Same as project_id (for consistency)
318
+ * @property {string} project_title - Project name
319
+ * @property {Array<string>} environments - List of configured environment names
320
+ * @property {string} default_environment - First environment or 'Local' fallback
321
+ * @property {boolean} has_environments_configured - Whether environments exist
322
+ *
323
+ * @throws {Error} If API key is invalid or project not found
324
+ *
325
+ * @example
326
+ * const projectInfo = await httpClient.getProjectInfo();
327
+ * console.log(projectInfo.project_id); // 1162
328
+ * console.log(projectInfo.environments); // ['Development', 'Staging', 'Production']
329
+ * console.log(projectInfo.default_environment); // 'Development'
330
+ */
331
+ async getProjectInfo() {
332
+ logger.debug('Fetching project information from API key...');
333
+
334
+ try {
335
+ const response = await this.get('/api/automation/project/info');
336
+
337
+ logger.info('Project info retrieved successfully', {
338
+ project_id: response.data.project_id,
339
+ project_title: response.data.project_title,
340
+ environments: response.data.environments,
341
+ has_environments: response.data.has_environments_configured
342
+ });
343
+
344
+ return response.data;
345
+ } catch (error) {
346
+ logger.error('Failed to fetch project info', {
347
+ error: error.message,
348
+ status: error.response?.status,
349
+ code: error.code
350
+ });
351
+
352
+ // Enhance error message for common scenarios
353
+ if (error.response?.status === 400) {
354
+ throw new Error(
355
+ 'No project associated with this API key. Please verify your API key is correctly configured.'
356
+ );
357
+ } else if (error.response?.status === 404) {
358
+ throw new Error(
359
+ 'Project not found or invalid. Please verify your API key is associated with a valid project.'
360
+ );
361
+ } else if (error.response?.status === 401 || error.response?.status === 403) {
362
+ throw new Error(
363
+ 'API key authentication failed. Please verify your API key is valid and not expired.'
364
+ );
365
+ }
366
+
367
+ throw error;
368
+ }
369
+ }
370
+
309
371
  /**
310
372
  * Set authorization header
311
373
  * @param {string} token - Authorization token
@@ -161,6 +161,18 @@ class CypressReporter {
161
161
  */
162
162
  async createRun(details) {
163
163
  try {
164
+ // Auto-configure project from API key if needed
165
+ await this.client.ensureProjectConfig();
166
+
167
+ // Use auto-detected environment if not explicitly provided
168
+ if (!this.config.environment && this.client._projectInfo) {
169
+ this.config.environment = this.client._projectInfo.default_environment;
170
+ logger.info('Using auto-detected default environment', {
171
+ environment: this.config.environment,
172
+ source: 'api_key_project_config'
173
+ });
174
+ }
175
+
164
176
  const browser = details.browser?.displayName || details.browser?.name || 'Cypress';
165
177
  const platform = details.system?.platform || process.platform;
166
178
  const os = this.detectOS(platform);
@@ -137,6 +137,18 @@ class JestReporter {
137
137
  */
138
138
  async createRun() {
139
139
  try {
140
+ // Auto-configure project from API key if needed
141
+ await this.client.ensureProjectConfig();
142
+
143
+ // Use auto-detected environment if not explicitly provided
144
+ if (!this.config.environment && this.client._projectInfo) {
145
+ this.config.environment = this.client._projectInfo.default_environment;
146
+ logger.info('Using auto-detected default environment', {
147
+ environment: this.config.environment,
148
+ source: 'api_key_project_config'
149
+ });
150
+ }
151
+
140
152
  const os = this.detectOS();
141
153
 
142
154
  const runOptions = {
@@ -209,6 +209,26 @@ class AppliqationReporter {
209
209
  return;
210
210
  }
211
211
 
212
+ // Auto-configure project from API key if needed
213
+ try {
214
+ await this.client.ensureProjectConfig();
215
+
216
+ // Use auto-detected environment if not explicitly provided
217
+ if (!this.config.environment && this.client._projectInfo) {
218
+ this.config.environment = this.client._projectInfo.default_environment;
219
+ logger.info('Using auto-detected default environment', {
220
+ environment: this.config.environment,
221
+ source: 'api_key_project_config'
222
+ });
223
+ }
224
+ } catch (error) {
225
+ logger.error('Failed to auto-configure from API key', {
226
+ error: error.message
227
+ });
228
+ console.error('\n❌ Auto-configuration failed:', error.message);
229
+ throw error;
230
+ }
231
+
212
232
  // Get project names that are actually running (honors --project filter)
213
233
  const runningProjectNames = this.getRunningProjectNames(suite);
214
234
  logger.debug('Projects actually running:', runningProjectNames);
@@ -546,11 +566,11 @@ class AppliqationReporter {
546
566
  this.trackResult(runInfo.runId, testResult);
547
567
 
548
568
  // Update counters
549
- if (testResult.status === 'passed') {
569
+ if (testResult.status === 'Pass') {
550
570
  this.passedTests++;
551
- } else if (testResult.status === 'failed') {
571
+ } else if (testResult.status === 'Fail') {
552
572
  this.failedTests++;
553
- } else if (testResult.status === 'skipped') {
573
+ } else if (testResult.status === 'Skipped') {
554
574
  this.skippedTests++;
555
575
  }
556
576
 
@@ -1465,27 +1485,13 @@ class AppliqationReporter {
1465
1485
  throw new Error('apiKey is required');
1466
1486
  }
1467
1487
 
1468
- if (!this.config.projectKey) {
1469
- throw new Error('projectKey is required');
1470
- }
1488
+ // projectKey is now optional with API key authentication
1489
+ // It will be auto-fetched from the API key's associated project
1490
+ // If not provided, auto-configuration will happen in onBegin()
1471
1491
 
1472
- // Environment is required - no default fallback
1473
- if (!this.config.environment) {
1474
- throw new Error(
1475
- '\n' +
1476
- '❌ Testing environment is required.\n' +
1477
- '\n' +
1478
- 'Please provide the environment in your test run command:\n' +
1479
- '\n' +
1480
- ' APPLIQATION_ENVIRONMENT=Production npx playwright test\n' +
1481
- '\n' +
1482
- 'Or set it in your .env file:\n' +
1483
- '\n' +
1484
- ' APPLIQATION_ENVIRONMENT=Production\n' +
1485
- '\n' +
1486
- 'Valid environments are configured in your Appliqation project settings.\n'
1487
- );
1488
- }
1492
+ // environment is now optional - will be auto-detected from project configuration
1493
+ // If not provided, the default environment from the project will be used
1494
+ // Manual configuration still supported for backward compatibility
1489
1495
 
1490
1496
  // Note: scenarioId, testSetId, and title are optional
1491
1497
  }