@alfresco/aca-playwright-shared 8.0.0-28849044572 → 8.0.0-28932229495

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.
@@ -2298,6 +2298,7 @@ class ActionsDropdownComponent extends BaseComponent {
2298
2298
  this.ruleActionLocator = this.getChild('aca-rule-action');
2299
2299
  this.addActionButtonLocator = this.getChild('[data-automation-id="rule-action-list-add-action-button"]');
2300
2300
  this.actionDropdownLocator = this.getChild('[data-automation-id="rule-action-select"]');
2301
+ this.selectActionLocator = this.actionDropdownLocator.locator('span', { hasText: 'Select an action' });
2301
2302
  this.actionAspectNameLocator = '[data-automation-id="header-aspect-name"] .adf-property-field';
2302
2303
  this.actionCheckInInputLocator = '[data-automation-id="header-description"] input';
2303
2304
  this.actionSimpleWorkflowStepInputLocator = '[data-automation-id="header-approve-step"] input';
@@ -2311,14 +2312,52 @@ class ActionsDropdownComponent extends BaseComponent {
2311
2312
  this.actionTransformAndCopyContentDestinationFolderLocator = '[data-automation-id="card-textitem-value-destination-folder"]';
2312
2313
  this.contentNodeSelectorSearchInput = '[data-automation-id="content-node-selector-search-input"]';
2313
2314
  }
2314
- async selectAction(action, index) {
2315
- if (index > 0) {
2315
+ async selectActions(actions) {
2316
+ for (const action of actions) {
2317
+ await this.selectSingleAction(action);
2318
+ }
2319
+ }
2320
+ normalizeAction(action) {
2321
+ if (typeof action === 'string') {
2322
+ return { type: action };
2323
+ }
2324
+ return action;
2325
+ }
2326
+ async selectSingleAction(action) {
2327
+ const { type, value, mimeType, destinationFolder } = this.normalizeAction(action);
2328
+ if (await this.selectActionLocator.isHidden()) {
2316
2329
  await this.addActionButtonLocator.click();
2317
2330
  }
2318
- await this.actionDropdownLocator.nth(index).hover({ timeout: 1000 });
2319
- await this.actionDropdownLocator.nth(index).click();
2320
- const option = this.getOptionLocator(action);
2321
- await option.click();
2331
+ await this.selectActionLocator.scrollIntoViewIfNeeded();
2332
+ await this.selectActionLocator.hover({ timeout: 1000 });
2333
+ await this.selectActionLocator.click();
2334
+ await this.getOptionLocator(type).click();
2335
+ const actionIndex = (await this.ruleActionLocator.count()) - 1;
2336
+ if (value) {
2337
+ await this.insertActionValues(type, value, actionIndex);
2338
+ }
2339
+ if (mimeType) {
2340
+ await this.selectMimeType(mimeType, actionIndex);
2341
+ }
2342
+ if (destinationFolder) {
2343
+ await this.selectDestinationFolderTransformAndCopyContent(actionIndex, destinationFolder);
2344
+ }
2345
+ }
2346
+ async insertActionValues(type, value, actionIndex) {
2347
+ switch (type) {
2348
+ case ActionType.AddAspect:
2349
+ await this.insertAddAspectActionValues(value, actionIndex);
2350
+ break;
2351
+ case ActionType.CheckIn:
2352
+ await this.insertCheckInActionValues(value, actionIndex);
2353
+ break;
2354
+ case ActionType.SpecialiseType:
2355
+ await this.insertSpecialiseTypeActionValues(value, actionIndex);
2356
+ break;
2357
+ case ActionType.SimpleWorkflow:
2358
+ await this.insertSimpleWorkflowActionValues(value, actionIndex);
2359
+ break;
2360
+ }
2322
2361
  }
2323
2362
  async dropdownSelection(selectValue, locator, index) {
2324
2363
  await this.ruleActionLocator.nth(index).locator(locator).click();
@@ -2454,6 +2493,7 @@ class ConditionComponent extends ManageRulesDialogComponent {
2454
2493
  await option.click();
2455
2494
  }
2456
2495
  async addCondition(fields, value, index, comparators) {
2496
+ await this.addConditionButton.first().scrollIntoViewIfNeeded();
2457
2497
  await this.addConditionButton.first().click();
2458
2498
  await this.selectField(fields, index);
2459
2499
  if (comparators) {
@@ -2467,7 +2507,9 @@ class ConditionComponent extends ManageRulesDialogComponent {
2467
2507
  }
2468
2508
  }
2469
2509
  async addConditionGroup(fields, value, index, comparators) {
2510
+ await this.addConditionGroupButton.last().scrollIntoViewIfNeeded();
2470
2511
  await this.addConditionGroupButton.last().click();
2512
+ await this.addConditionButton.nth(index).scrollIntoViewIfNeeded();
2471
2513
  await this.addConditionButton.nth(index).click();
2472
2514
  await this.selectField(fields, index);
2473
2515
  if (comparators) {
@@ -2475,6 +2517,18 @@ class ConditionComponent extends ManageRulesDialogComponent {
2475
2517
  }
2476
2518
  await this.valueField.nth(index).fill(value);
2477
2519
  }
2520
+ async addConditions(conditions) {
2521
+ for (let i = 0; i < conditions.length; i++) {
2522
+ const { field, value, comparator } = conditions[i];
2523
+ await this.addCondition(field, value, i, comparator);
2524
+ }
2525
+ }
2526
+ async addConditionGroups(conditions) {
2527
+ for (let i = 0; i < conditions.length; i++) {
2528
+ const { field, value, comparator } = conditions[i];
2529
+ await this.addConditionGroup(field, value, i, comparator);
2530
+ }
2531
+ }
2478
2532
  }
2479
2533
 
2480
2534
  /*!
@@ -3380,7 +3434,7 @@ class Breadcrumb extends BaseComponent {
3380
3434
  const itemElements = await this.page.$$('adf-breadcrumb .adf-breadcrumb-item');
3381
3435
  const itemTexts = await Promise.all(itemElements.map(async (elem) => {
3382
3436
  const text = await elem.innerText();
3383
- return text.split('\nchevron_right')[0];
3437
+ return text.split('\nchevron_right')[0].trim();
3384
3438
  }));
3385
3439
  return itemTexts;
3386
3440
  }
@@ -4578,7 +4632,7 @@ const getGlobalConfig = {
4578
4632
  /* Retry on CI only */
4579
4633
  retries: env.CI ? 2 : 0,
4580
4634
  /* Opt out of parallel tests on CI. */
4581
- workers: 3,
4635
+ workers: Number(env.PLAYWRIGHT_WORKERS) || 3,
4582
4636
  /* Reporter to use. See https://playwright.dev/docs/test-reporters */
4583
4637
  reporter: [['list'], ...getReporter()],
4584
4638
  globalSetup: require.resolve('./global.setup'),
@@ -4744,7 +4798,7 @@ class ApiClientFactory {
4744
4798
  await this.alfrescoApi.login(user.username, user.password);
4745
4799
  }
4746
4800
  catch (error) {
4747
- logger.error(`[API Client Factory] Log in user ${user.username} failed ${error}`);
4801
+ logger.error(`[API Client Factory] Log in user ${user.username} failed ${JSON.stringify(error)}`);
4748
4802
  throw error;
4749
4803
  }
4750
4804
  }
@@ -4755,7 +4809,7 @@ class ApiClientFactory {
4755
4809
  return await peopleApi.createPerson(person);
4756
4810
  }
4757
4811
  catch (error) {
4758
- if (String(error).includes('409')) {
4812
+ if (JSON.stringify(error).includes('409')) {
4759
4813
  logger.warn(`[API Client Factory] createUser: user "${user.username}" already exists, skipping creation`);
4760
4814
  return null;
4761
4815
  }
@@ -5072,7 +5126,7 @@ class FileActionsApi {
5072
5126
  return result;
5073
5127
  }
5074
5128
  catch (error) {
5075
- logger.error(`Failed to upload file: ${fileName}: ${error}`);
5129
+ logger.error(`Failed to upload file: ${fileName}: ${JSON.stringify(error)}`);
5076
5130
  return Promise.reject(error);
5077
5131
  }
5078
5132
  }
@@ -5169,16 +5223,10 @@ class FileActionsApi {
5169
5223
  }
5170
5224
  }
5171
5225
  async waitForNodes(searchTerm, data) {
5172
- logger.info(`waitForNodes: Waiting for ${data.expect} node(s) matching "${searchTerm}"`);
5173
5226
  const predicate = (totalItems) => totalItems === data.expect;
5174
- let pollCount = 0;
5175
5227
  const apiCall = async () => {
5176
5228
  try {
5177
- const totalItems = (await this.queryNodesNames(searchTerm)).list?.pagination?.totalItems || 0;
5178
- if (pollCount++ % 4 === 0) {
5179
- logger.info(`waitForNodes: "${searchTerm}" — found ${totalItems}, expecting ${data.expect}`);
5180
- }
5181
- return totalItems;
5229
+ return (await this.queryNodesNames(searchTerm)).list?.pagination?.totalItems || 0;
5182
5230
  }
5183
5231
  catch {
5184
5232
  return 0;
@@ -5186,6 +5234,7 @@ class FileActionsApi {
5186
5234
  };
5187
5235
  try {
5188
5236
  await waitForApi(apiCall, predicate, 30, 2500);
5237
+ logger.info(`waitForNodes: Found ${data.expect} node(s) matching "${searchTerm}"`);
5189
5238
  }
5190
5239
  catch {
5191
5240
  const actual = await apiCall();
@@ -5349,9 +5398,7 @@ class SharedLinksApi {
5349
5398
  const sharedFiles = (await this.getSharedLinks()).list?.entries?.map((link) => link.entry.nodeId) ?? [];
5350
5399
  const foundItems = fileIds.every((id) => sharedFiles.includes(id));
5351
5400
  if (!foundItems) {
5352
- const message = 'Not all files are shared yet';
5353
- logger.error(message);
5354
- throw new Error(message);
5401
+ throw new Error('Not all files are shared yet');
5355
5402
  }
5356
5403
  };
5357
5404
  await Utils.retryCall(sharedFile);
@@ -5645,7 +5692,7 @@ class NodesApi {
5645
5692
  return await this.createNode('cm:content', name, parentId, title, description, null, author, majorVersion, aspectNames);
5646
5693
  }
5647
5694
  catch (error) {
5648
- const message = `${this.constructor.name} ${this.createFile.name}: ${error}`;
5695
+ const message = `${this.constructor.name} ${this.createFile.name}: ${error instanceof Error ? error.message : JSON.stringify(error)}`;
5649
5696
  logger.error(message);
5650
5697
  throw new Error(message);
5651
5698
  }
@@ -5710,7 +5757,14 @@ class NodesApi {
5710
5757
  });
5711
5758
  }
5712
5759
  catch (error) {
5713
- const message = `${this.constructor.name} ${this.createNode.name}: ${error}`;
5760
+ if (JSON.stringify(error).includes('409')) {
5761
+ logger.warn(`${this.constructor.name} ${this.createNode.name}: node "${name}" already exists in parent "${parentId}", retrieving existing node`);
5762
+ const existingNodeId = await this.getNodeIdFromParent(name, parentId);
5763
+ if (existingNodeId) {
5764
+ return this.getNodeById(existingNodeId);
5765
+ }
5766
+ }
5767
+ const message = `${this.constructor.name} ${this.createNode.name}: ${error instanceof Error ? error.message : JSON.stringify(error)}`;
5714
5768
  logger.error(message);
5715
5769
  throw new Error(message);
5716
5770
  }
@@ -6096,9 +6150,15 @@ class SitesApi {
6096
6150
  return await this.apiService.sites.createSite(site);
6097
6151
  }
6098
6152
  catch (error) {
6099
- const message = `SitesApi ${this.createSite.name}: ${error}`;
6100
- logger.error(message);
6101
- throw new Error(message);
6153
+ if (JSON.stringify(error).includes('409')) {
6154
+ logger.warn(`[SitesApi] createSite: site "${siteId || title}" already exists, skipping creation`);
6155
+ return this.getSite(siteId || title);
6156
+ }
6157
+ else {
6158
+ const message = `SitesApi ${this.createSite.name}: ${JSON.stringify(error)}`;
6159
+ logger.error(message);
6160
+ throw new Error(message);
6161
+ }
6102
6162
  }
6103
6163
  }
6104
6164
  async getDocLibId(siteId) {
@@ -6267,6 +6327,116 @@ class SearchApi {
6267
6327
  return new ResultSetPaging();
6268
6328
  }
6269
6329
  }
6330
+ async searchForNode(fileName, options) {
6331
+ const query = {
6332
+ query: {
6333
+ query: `cm:name:"${fileName}"`,
6334
+ language: 'afts'
6335
+ },
6336
+ include: ['path', 'allowableOperations', 'properties'],
6337
+ paging: {
6338
+ skipCount: 0,
6339
+ maxItems: 25
6340
+ },
6341
+ filterQueries: [
6342
+ {
6343
+ query: "+TYPE:'cm:folder' OR +TYPE:'cm:content'"
6344
+ },
6345
+ {
6346
+ query: "-TYPE:'cm:thumbnail' AND -TYPE:'cm:failedThumbnail' AND -TYPE:'cm:rating'"
6347
+ },
6348
+ {
6349
+ query: '-cm:creator:System'
6350
+ },
6351
+ {
6352
+ query: "-TYPE:'st:site' AND -ASPECT:'st:siteContainer' AND -ASPECT:'sys:hidden'"
6353
+ },
6354
+ {
6355
+ query: "-TYPE:'dl:dataList' AND -TYPE:'dl:todoList' AND -TYPE:'dl:issue'"
6356
+ },
6357
+ {
6358
+ query: "-TYPE:'fm:topic' AND -TYPE:'fm:post'"
6359
+ },
6360
+ {
6361
+ query: "-TYPE:'lnk:link'"
6362
+ },
6363
+ {
6364
+ query: "-PATH:'//cm:wiki/*'"
6365
+ },
6366
+ {
6367
+ query: "+TYPE:'cm:content'"
6368
+ }
6369
+ ],
6370
+ facetQueries: undefined,
6371
+ facetIntervals: undefined,
6372
+ facetFields: {
6373
+ facets: [
6374
+ {
6375
+ field: 'creator',
6376
+ mincount: 1,
6377
+ label: 'SEARCH.FACET_FIELDS.CREATOR'
6378
+ },
6379
+ {
6380
+ field: 'modifier',
6381
+ mincount: 1,
6382
+ label: 'SEARCH.FACET_FIELDS.MODIFIER'
6383
+ }
6384
+ ]
6385
+ },
6386
+ sort: [
6387
+ {
6388
+ type: 'SCORE',
6389
+ field: 'score',
6390
+ ascending: false
6391
+ }
6392
+ ],
6393
+ highlight: {
6394
+ prefix: "<span class='aca-highlight'>",
6395
+ postfix: '</span>',
6396
+ fields: [
6397
+ {
6398
+ field: 'cm:title'
6399
+ },
6400
+ {
6401
+ field: 'cm:name'
6402
+ },
6403
+ {
6404
+ field: 'cm:description',
6405
+ snippetCount: 1
6406
+ },
6407
+ {
6408
+ field: 'cm:content',
6409
+ snippetCount: 1
6410
+ }
6411
+ ]
6412
+ },
6413
+ facetFormat: 'V2'
6414
+ };
6415
+ let result;
6416
+ let retryCount = 0;
6417
+ const retryLimit = options?.maxRetries ?? 90;
6418
+ do {
6419
+ try {
6420
+ result = await this.apiService.search.search(query);
6421
+ }
6422
+ catch {
6423
+ result = new ResultSetPaging();
6424
+ }
6425
+ if ((result.list?.entries?.length ?? 0) === 0) {
6426
+ retryCount++;
6427
+ if (retryCount % 10 === 0) {
6428
+ logger.info(`searchForNode: Still waiting for file "${fileName}" after ${retryCount} retries (max ${retryLimit}).`);
6429
+ }
6430
+ if (retryCount >= retryLimit) {
6431
+ logger.error(`searchForNode: File "${fileName}" not found after ${retryLimit} retries.`);
6432
+ throw new Error(`File with name ${fileName} not found after ${retryLimit} retries`);
6433
+ }
6434
+ await Utils.delayInSeconds(1);
6435
+ }
6436
+ } while ((result.list?.entries?.length ?? 0) === 0);
6437
+ logger.info(`searchForNode: Search succeeded for file "${fileName}"`);
6438
+ return result;
6439
+ }
6270
6440
  async getTotalItems(username) {
6271
6441
  return (await this.querySearchFiles(username)).list?.pagination?.totalItems ?? 0;
6272
6442
  }
@@ -6316,8 +6486,24 @@ class SearchApi {
6316
6486
  return result.list?.pagination?.count ?? 0;
6317
6487
  }
6318
6488
  catch (error) {
6319
- logger.error(`waitForFolderPathIndexing failed for folderId "${folderId}": ${error}`);
6320
- throw error;
6489
+ const errorMessage = `waitForFolderPathIndexing failed for folderId "${folderId}": ${JSON.stringify(error)}`;
6490
+ logger.error(errorMessage);
6491
+ throw new Error(errorMessage);
6492
+ }
6493
+ }
6494
+ async waitFileForSearchIndexing(fileName, maxRetries) {
6495
+ try {
6496
+ const result = await this.searchForNode(fileName, { maxRetries: maxRetries });
6497
+ const entryNames = (result.list?.entries ?? []).map((entry) => entry.entry?.name).filter((name) => Boolean(name));
6498
+ if (!entryNames.includes(fileName)) {
6499
+ throw new Error(`File "${fileName}" not found in search results. Found: [${entryNames.join(', ')}]`);
6500
+ }
6501
+ logger.info(`waitFileForSearchIndexing: File "${fileName}" is indexed.`);
6502
+ }
6503
+ catch (error) {
6504
+ const errorMessage = `waitFileForSearchIndexing failed for file "${fileName}": ${JSON.stringify(error)}`;
6505
+ logger.error(errorMessage);
6506
+ throw new Error(errorMessage);
6321
6507
  }
6322
6508
  }
6323
6509
  }