[ACS-12817] automated ACS-12663 and updated lock api

This commit is contained in:
Adam Świderski
2026-09-16 14:57:37 +02:00
committed by Adam Świderski
parent 60f5ded8fb
commit 86e1b33dec
9 changed files with 142 additions and 90 deletions
@@ -51,10 +51,6 @@ test.describe('Copy actions', () => {
}
});
test.afterAll(async () => {
await Utils.deleteNodesSitesEmptyTrashcan(nodesApi, trashcanApi, 'afterAll failed');
});
test.beforeEach(async ({ personalFiles, page }) => {
sourceFile = `source-file-${Utils.random()}.txt`;
sourceFileInsideFolder = `source-file-inside-folder-${Utils.random()}.txt`;
@@ -72,6 +68,10 @@ test.describe('Copy actions', () => {
await personalFiles.navigate();
});
test.afterAll(async () => {
await Utils.deleteNodesSitesEmptyTrashcan(nodesApi, trashcanApi, 'afterAll failed');
});
const copyContentInPersonalFiles = async (personalFilesPage: PersonalFilesPage, sourceFileList: string[], destinationName: string) => {
await personalFilesPage.copyOrMoveContentInDatatable(sourceFileList, destinationName, 'Copy');
const msg = await personalFilesPage.snackBar.message.innerText();
@@ -148,8 +148,7 @@ test.describe('Copy actions', () => {
});
test('[XAT-4947] Copy locked file', async ({ personalFiles }) => {
const lockType = 'ALLOW_OWNER_CHANGES';
await nodesApi.lockNodes([sourceFileId], lockType);
await nodesApi.checkoutNodes([sourceFileId]);
await Utils.reloadPageIfRowNotVisible(personalFiles, sourceFile);
await copyContentInPersonalFiles(personalFiles, [sourceFile], destinationFolder);
expect.soft(await personalFiles.dataTable.isItemPresent(sourceFile)).toBe(true);
@@ -159,8 +158,7 @@ test.describe('Copy actions', () => {
});
test('[XAT-4948] Copy folder that contains locked file', async ({ personalFiles }) => {
const lockType = 'ALLOW_OWNER_CHANGES';
await nodesApi.lockNodes([sourceFileInsideFolderId], lockType);
await nodesApi.checkoutNodes([sourceFileInsideFolderId]);
await copyFolderAndVerifyContent(personalFiles);
});
@@ -130,8 +130,7 @@ test.describe('Move actions', () => {
});
test('[XAT-4989] Move locked file', async ({ personalFiles }) => {
const lockType = 'ALLOW_OWNER_CHANGES';
await nodesApi.lockNodes([sourceFileId], lockType);
await nodesApi.checkoutNodes([sourceFileId]);
await Utils.reloadPageIfRowNotVisible(personalFiles, sourceFile);
await moveContentInPersonalFiles(personalFiles, [sourceFile], destinationFolder);
const msg = await personalFiles.snackBar.message.innerText();
@@ -168,8 +167,7 @@ test.describe('Move actions', () => {
async function moveFolderWithContent(personalFiles: PersonalFilesPage, lockedFile: boolean) {
if (lockedFile) {
const lockType = 'ALLOW_OWNER_CHANGES';
await nodesApi.lockNodes([sourceFileInsideFolderId], lockType);
await nodesApi.checkoutNodes([sourceFileInsideFolderId]);
}
await Utils.reloadPageIfRowNotVisible(personalFiles, sourceFolder);
await moveContentInPersonalFiles(personalFiles, [sourceFolder], destinationFolder);
@@ -104,7 +104,7 @@ test.describe('Delete and undo delete', () => {
fileLocked4Id = (await nodesApi.createFile(fileLocked4, folder5Id)).entry.id;
await nodesApi.createFile(file2InFolder, folder6Id);
await nodesApi.lockNodes([fileLocked1Id, fileLocked2Id, fileLocked3Id, fileLocked4Id], 'FULL');
await nodesApi.checkoutNodes([fileLocked1Id, fileLocked2Id, fileLocked3Id, fileLocked4Id]);
});
test.beforeEach(async ({ loginPage, personalFiles }) => {
@@ -114,7 +114,7 @@ test.describe('Delete and undo delete', () => {
});
test.afterAll(async () => {
await nodesApi.unlockNodes([fileLocked1Id, fileLocked2Id, fileLocked3Id, fileLocked4Id]);
await nodesApi.cancelCheckout([fileLocked1Id, fileLocked2Id, fileLocked3Id, fileLocked4Id]);
await Utils.deleteNodesSitesEmptyTrashcan(nodesApi, trashcanApi, 'afterAll failed');
});
@@ -26,70 +26,140 @@ import { expect } from '@playwright/test';
import { ApiClientFactory, NodesApi, Utils, test, TrashcanApi, FileActionsApi, TEST_FILES } from '@alfresco/aca-playwright-shared';
test.describe('Edit offline - on Personal Files', () => {
const apiClientFactory = new ApiClientFactory();
const username = `user-${Utils.random()}`;
let nodesApi: NodesApi;
let trashcanApi: TrashcanApi;
let fileActionsApi: FileActionsApi;
let parentPFId: string;
let fileLockedId: string;
let fileLocked2Id: string;
const username = `user-${Utils.random()}`;
const file1 = `file1-${Utils.random()}.docx`;
const fileLocked = `file-locked-${Utils.random()}.docx`;
const fileLocked2 = `file-locked2-${Utils.random()}.docx`;
const parentPF = `parentPersonal-${Utils.random()}`;
test.beforeAll(async () => {
try {
await apiClientFactory.setUpAcaBackend('admin');
await apiClientFactory.createUser({ username });
nodesApi = await NodesApi.initialize(username, username);
trashcanApi = await TrashcanApi.initialize(username, username);
fileActionsApi = await FileActionsApi.initialize(username, username);
parentPFId = (await nodesApi.createFolder(parentPF)).entry.id;
fileLockedId = (await fileActionsApi.uploadFileWithRename(TEST_FILES.DOCX.path, fileLocked, parentPFId)).entry.id;
fileLocked2Id = (await fileActionsApi.uploadFileWithRename(TEST_FILES.DOCX.path, fileLocked2, parentPFId)).entry.id;
await fileActionsApi.uploadFileWithRename(TEST_FILES.DOCX.path, file1, parentPFId);
await nodesApi.lockNodes([fileLockedId, fileLocked2Id]);
} catch (error) {
console.error(`beforeAll failed : ${error}`);
}
});
test.beforeEach(async ({ loginPage, personalFiles }) => {
await Utils.tryLoginUser(loginPage, username, username, 'beforeEach failed');
await personalFiles.dataTable.performClickFolderOrFileToOpen(parentPF);
const apiClientFactory = new ApiClientFactory();
await apiClientFactory.setUpAcaBackend('admin');
await apiClientFactory.createUser({ username });
nodesApi = await NodesApi.initialize(username, username);
trashcanApi = await TrashcanApi.initialize(username, username);
fileActionsApi = await FileActionsApi.initialize(username, username);
});
test.afterAll(async () => {
await Utils.deleteNodesSitesEmptyTrashcan(nodesApi, trashcanApi, 'afterAll failed');
});
test('[XAT-5304] File is locked and downloaded when clicking Edit offline', async ({ personalFiles }) => {
await personalFiles.dataTable.selectItems(file1);
await personalFiles.acaHeader.clickMoreActions();
const [download] = await Promise.all([
personalFiles.page.waitForEvent('download', { timeout: 5000 }),
personalFiles.matMenu.clickMenuItem('Edit Offline')
]);
expect(download.suggestedFilename()).toBe(file1);
test.describe('[XAT-5304] File is locked and downloaded when clicking Edit offline', () => {
const file5304 = `file-5304-${Utils.random()}.docx`;
let file5304Id: string;
test.beforeAll(async () => {
try {
file5304Id = (await fileActionsApi.uploadFileWithRename(TEST_FILES.DOCX.path, file5304)).entry.id;
} catch (error) {
console.error(`beforeAll failed : ${error}`);
}
});
test.beforeEach(async ({ loginPage, personalFiles }) => {
await Utils.tryLoginUser(loginPage, username, username, 'beforeEach failed');
await personalFiles.navigate();
});
test.afterAll(async () => {
await nodesApi.cancelCheckout([file5304Id]);
});
test('[XAT-5304] File is locked and downloaded when clicking Edit offline', async ({ personalFiles }) => {
await personalFiles.dataTable.selectItems(file5304);
await personalFiles.acaHeader.clickMoreActions();
const [download] = await Promise.all([
personalFiles.page.waitForEvent('download', { timeout: 5000 }),
personalFiles.matMenu.clickMenuItem('Edit Offline')
]);
expect(download.suggestedFilename()).toBe(file5304);
});
});
test('[XAT-5305] Lock information is displayed', async ({ personalFiles }) => {
expect(await personalFiles.dataTable.isItemPresent(fileLocked2)).toBe(true);
expect(await personalFiles.dataTable.getLockOwner(fileLocked2)).toContain(username);
test.describe('[XAT-5305] Lock information is displayed', () => {
const fileLocked5305 = `file-locked-5305-${Utils.random()}.docx`;
let fileLocked5305Id: string;
test.beforeAll(async () => {
try {
fileLocked5305Id = (await fileActionsApi.uploadFileWithRename(TEST_FILES.DOCX.path, fileLocked5305)).entry.id;
await nodesApi.checkoutNodes([fileLocked5305Id]);
} catch (error) {
console.error(`beforeAll failed : ${error}`);
}
});
test.beforeEach(async ({ loginPage, personalFiles }) => {
await Utils.tryLoginUser(loginPage, username, username, 'beforeEach failed');
await personalFiles.navigate();
});
test.afterAll(async () => {
await nodesApi.cancelCheckout([fileLocked5305Id]);
});
test('[XAT-5305] Lock information is displayed', async ({ personalFiles }) => {
expect(await personalFiles.dataTable.isItemPresent(fileLocked5305)).toBe(true);
expect(await personalFiles.dataTable.getLockOwner(fileLocked5305)).toContain(username);
});
});
test('[XAT-5306] Cancel Editing unlocks the file', async ({ personalFiles }) => {
await personalFiles.dataTable.selectItems(fileLocked);
await personalFiles.acaHeader.clickMoreActions();
await personalFiles.matMenu.clickMenuItemFromHeaderMenu('Cancel Editing');
test.describe('[XAT-5306] Cancel Editing unlocks the file', () => {
const fileLocked5306 = `file-locked-5306-${Utils.random()}.docx`;
let fileLocked5306Id: string;
expect(await nodesApi.isFileLockedWrite(fileLockedId), `${fileLocked} is still locked`).not.toEqual('WRITE_LOCK');
test.beforeAll(async () => {
try {
fileLocked5306Id = (await fileActionsApi.uploadFileWithRename(TEST_FILES.DOCX.path, fileLocked5306)).entry.id;
await nodesApi.checkoutNodes([fileLocked5306Id]);
} catch (error) {
console.error(`beforeAll failed : ${error}`);
}
});
test.beforeEach(async ({ loginPage, personalFiles }) => {
await Utils.tryLoginUser(loginPage, username, username, 'beforeEach failed');
await personalFiles.navigate();
});
test('[XAT-5306] Cancel Editing unlocks the file', async ({ personalFiles }) => {
await personalFiles.dataTable.selectItems(fileLocked5306);
await personalFiles.acaHeader.clickMoreActions();
await personalFiles.matMenu.clickMenuItemFromHeaderMenu('Cancel Editing');
expect(await nodesApi.isFileLockedWrite(fileLocked5306Id), `${fileLocked5306} is still locked`).not.toEqual('WRITE_LOCK');
});
});
test.describe('[XAT-20171] Cancel Editing option should not persists after uploading a new file version', () => {
const file20171 = `file-20171-${Utils.random()}.docx`;
test.beforeAll(async () => {
try {
await fileActionsApi.uploadFileWithRename(TEST_FILES.JPG_FILE.path, file20171);
} catch (error) {
console.error(`beforeAll failed : ${error}`);
}
});
test.beforeEach(async ({ loginPage, personalFiles }) => {
await Utils.tryLoginUser(loginPage, username, username, 'beforeEach failed');
await personalFiles.navigate();
});
test('[XAT-20171] Cancel Editing option should not persists after uploading a new file version', async ({ personalFiles }) => {
await personalFiles.dataTable.selectItems(file20171);
await personalFiles.acaHeader.clickMoreActions();
const [fileChooser] = await Promise.all([
personalFiles.page.waitForEvent('filechooser'),
personalFiles.acaHeader.matMenu.clickMenuItem('Upload New Version')
]);
await fileChooser.setFiles(TEST_FILES.PNG_FILE.path);
await personalFiles.uploadNewVersionDialog.uploadButton.click();
expect(await personalFiles.dataTable.isItemPresent(TEST_FILES.PNG_FILE.name)).toBe(true);
await personalFiles.dataTable.selectItems(TEST_FILES.PNG_FILE.name);
await personalFiles.acaHeader.clickMoreActions();
await expect(personalFiles.matMenu.getButtonByText('Upload New Version')).toBeVisible();
});
});
});
@@ -122,7 +122,7 @@ test.describe('Special permissions : ', () => {
fileSharedFavLockedId
]);
await managerNodeActions.lockNodes([fileLockedId, fileFavLockedId, fileSharedLockedId, fileSharedFavLockedId]);
await managerNodeActions.checkoutNodes([fileLockedId, fileFavLockedId, fileSharedLockedId, fileSharedFavLockedId]);
await Promise.all([
consumerFavoritesActions.waitForApi(userConsumer, { expect: consumerFavoritesTotalItems + 6 }),
@@ -243,7 +243,7 @@ test.describe('Special permissions : ', () => {
fileLockedByUserId = (await managerNodeActions.createFile(testData.fileLockedByUser.name, docLibId, '', '', '', true, ['cm:versionable'])).entry
.id;
await demotedUserActions.lockNodes([fileLockedByUserId]);
await demotedUserActions.checkoutNodes([fileLockedByUserId]);
await demotedUserFavoritesActions.addFavoriteById('file', fileLockedByUserId);
await demotedUserShareActions.shareFileById(fileLockedByUserId);
await managerSiteActions.updateSiteMember(sitePrivate, userDemoted, Site.RoleEnum.SiteConsumer);
@@ -301,7 +301,7 @@ test.describe('Special permissions : ', () => {
fileLockedByUserId = (await managerNodeActions.createFile(testData.fileLockedByUser.name, docLibId, '', '', '', true, ['cm:versionable'])).entry
.id;
await demotedUserActions.lockNodes([fileLockedByUserId]);
await demotedUserActions.checkoutNodes([fileLockedByUserId]);
await demotedUserShareActions.shareFileById(fileLockedByUserId);
await managerFavoritesActions.addFavoriteById('file', fileLockedByUserId);
@@ -142,7 +142,7 @@ test.describe('Upload new version', () => {
fileLocked1Id = (await nodesApi.createFile(fileToUpload1, parentPFId)).entry.id;
fileLocked2Id = (await nodesApi.createFile(fileLocked2, parentPFId)).entry.id;
await nodesApi.lockNodes([fileLocked1Id, fileLocked2Id]);
await nodesApi.checkoutNodes([fileLocked1Id, fileLocked2Id]);
});
test.beforeEach(async ({ loginPage, personalFiles }) => {
@@ -238,7 +238,6 @@ test.describe('viewer action file', () => {
const username = `user-${Utils.random()}`;
const fileForCancelEditing = `playwright-file2-${Utils.random()}.docx`;
let folderIdCancelEdit: string;
let workingCopyName: string;
let nodesApi: NodesApi;
let trashcanApi: TrashcanApi;
@@ -251,8 +250,7 @@ test.describe('viewer action file', () => {
const { fileActionsApi } = apis;
folderIdCancelEdit = (await nodesApi.createFolder(`viewer-action-5424-${Utils.random()}`)).entry.id;
const fileForCancelEditingId = (await fileActionsApi.uploadFile(TEST_FILES.DOCX.path, fileForCancelEditing, folderIdCancelEdit)).entry.id;
const workingCopy = await fileActionsApi.checkoutNode(fileForCancelEditingId);
workingCopyName = workingCopy.entry.name;
await nodesApi.checkoutNodes([fileForCancelEditingId]);
await fileActionsApi.isFileCheckedOutWithRetry(fileForCancelEditingId, true);
} catch (error) {
console.error(`beforeAll failed: ${error}`);
@@ -270,7 +268,7 @@ test.describe('viewer action file', () => {
});
test('[XAT-5424] Viewer - Cancel Editing action - Personal Files', async ({ personalFiles }) => {
await openFileInViewer(personalFiles, workingCopyName);
await openFileInViewer(personalFiles, fileForCancelEditing);
await personalFiles.viewer.toolbar.clickMoreActions();
await personalFiles.matMenu.clickMenuItem('Cancel Editing');
await personalFiles.viewer.waitForViewerToOpen();
@@ -322,7 +320,7 @@ test.describe('viewer action file', () => {
await fileActionsApi.uploadFileWithRename(TEST_FILES.JPG_FILE.path, file5714, folder5714Id);
await fileActionsApi.uploadFileWithRename(TEST_FILES.JPG_FILE.path, file5717, folder5717Id);
await fileActionsApi.uploadFileWithRename(TEST_FILES.JPG_FILE.path, file5720, folder5720Id);
await fileActionsApi.lockNodes([file17781Id]);
await nodesApi.checkoutNodes([file17781Id]);
} catch (error) {
console.error(`beforeAll failed: ${error}`);
throw error;
@@ -127,18 +127,6 @@ export class FileActionsApi {
}
}
async lockNodes(nodeIds: string[], lockType: string = 'ALLOW_OWNER_CHANGES'): Promise<void> {
try {
for (const nodeId of nodeIds) {
await this.apiService.nodes.lockNode(nodeId, { type: lockType });
}
} catch {}
}
async checkoutNode(nodeId: string): Promise<NodeEntry> {
return this.apiService.nodes.checkoutNode(nodeId);
}
async getNodeById(id: string): Promise<NodeEntry | null> {
try {
return this.apiService.nodes.getNode(id);
@@ -208,23 +208,23 @@ export class NodesApi {
}
}
async lockNodes(nodeIds: string[], lockType: string = 'ALLOW_OWNER_CHANGES') {
async checkoutNodes(nodeIds: string[]) {
try {
for (const nodeId of nodeIds) {
await this.apiService.nodes.lockNode(nodeId, { type: lockType });
await this.apiService.nodes.checkoutNode(nodeId);
}
} catch (error) {
logger.error(`${this.constructor.name} ${this.lockNodes.name}: ${error}`);
logger.error(`${this.constructor.name} ${this.checkoutNodes.name}: ${JSON.stringify(error)}`);
}
}
async unlockNodes(nodeIds: string[]) {
async cancelCheckout(nodeIds: string[]) {
try {
for (const nodeId of nodeIds) {
await this.apiService.nodes.unlockNode(nodeId);
await this.apiService.nodes.cancelCheckoutNode(nodeId);
}
} catch (error) {
logger.error(`${this.constructor.name} ${this.unlockNodes.name}: ${error}`);
logger.error(`${this.constructor.name} ${this.cancelCheckout.name}: ${JSON.stringify(error)}`);
}
}