diff --git a/e2e/playwright/viewer/src/tests/viewer-file-types.e2e.ts b/e2e/playwright/viewer/src/tests/viewer-file-types.e2e.ts index 02586b05d..6849cf803 100644 --- a/e2e/playwright/viewer/src/tests/viewer-file-types.e2e.ts +++ b/e2e/playwright/viewer/src/tests/viewer-file-types.e2e.ts @@ -51,6 +51,7 @@ test.describe('viewer file types', () => { const randomMp4Name = `${TEST_FILES.MP4_FILE.name}-${randomString}.mp4`; const randomWebmName = `${TEST_FILES.WEBM_FILE.name}-${randomString}.webm`; const randomAzw3Name = `${TEST_FILES.AZW3_FILE.name}-${randomString}.azw3`; + const randomPdfJp2Name = `${TEST_FILES.PDF_JP2_FILE.name}-${randomString}.pdf`; let nodesApi: NodesApi; let trashcanApi: TrashcanApi; let fileActionApi: FileActionsApi; @@ -58,16 +59,7 @@ test.describe('viewer file types', () => { test.beforeAll(async () => { const apiClientFactory = new ApiClientFactory(); await apiClientFactory.setUpAcaBackend('admin'); - - try { - await apiClientFactory.createUser({ username }); - } catch (exception) { - if (JSON.parse(exception.message).error.statusCode !== 409) { - const errorMessage = `----- beforeAll failed : ${exception}`; - logger.error(errorMessage); - throw new Error(errorMessage); - } - } + await apiClientFactory.createUser({ username }); nodesApi = await NodesApi.initialize(username, username); fileActionApi = await FileActionsApi.initialize(username, username); @@ -83,7 +75,8 @@ test.describe('viewer file types', () => { { path: TEST_FILES.MP3_FILE.path, name: randomMp3Name }, { path: TEST_FILES.MP4_FILE.path, name: randomMp4Name }, { path: TEST_FILES.WEBM_FILE.path, name: randomWebmName }, - { path: TEST_FILES.AZW3_FILE.path, name: randomAzw3Name } + { path: TEST_FILES.AZW3_FILE.path, name: randomAzw3Name }, + { path: TEST_FILES.PDF_JP2_FILE.path, name: randomPdfJp2Name } ]; for (const file of filesToUpload) { @@ -92,6 +85,7 @@ test.describe('viewer file types', () => { await fileActionApi.waitForNodes(randomWebmName, { expect: 1 }); await fileActionApi.waitForNodes(randomAzw3Name, { expect: 1 }); + await fileActionApi.waitForNodes(randomPdfJp2Name, { expect: 1 }); }); test.beforeEach(async ({ loginPage }) => { @@ -201,4 +195,8 @@ test.describe('viewer file types', () => { await personalFiles.viewer.thumbnailsCloseButton.click(); await expect(personalFiles.viewer.thumbnailsPages.first()).toBeHidden(); }); + + test('[XAT-19373] PDFs containing JP2 images are displayed properly', async ({ personalFiles }) => { + await checkViewerDisplay(personalFiles, randomPdfJp2Name, 'viewerDocument'); + }); }); diff --git a/projects/aca-playwright-shared/src/api/api-client-factory.ts b/projects/aca-playwright-shared/src/api/api-client-factory.ts index 19a0c7db4..380eb40b5 100644 --- a/projects/aca-playwright-shared/src/api/api-client-factory.ts +++ b/projects/aca-playwright-shared/src/api/api-client-factory.ts @@ -162,8 +162,12 @@ export class ApiClientFactory { try { return await peopleApi.createPerson(person); } catch (error) { + if (String(error).includes('409')) { + logger.warn(`[API Client Factory] createUser: user "${user.username}" already exists, skipping creation`); + return null; + } logger.error(`[API Client Factory] createUser failed: ${error}`); - return null; + throw error; } } diff --git a/projects/aca-playwright-shared/src/api/file-actions.ts b/projects/aca-playwright-shared/src/api/file-actions.ts index 4bc8f6ed8..5827915c2 100644 --- a/projects/aca-playwright-shared/src/api/file-actions.ts +++ b/projects/aca-playwright-shared/src/api/file-actions.ts @@ -42,11 +42,18 @@ export class FileActionsApi { async uploadFile(fileLocation: string, fileName: string, parentFolderId: string): Promise { const file = fs.createReadStream(fileLocation); - return this.apiService.upload.uploadFile(file, '', parentFolderId, null, { - name: fileName, - nodeType: 'cm:content', - renditions: 'doclib' - }); + try { + const result = await this.apiService.upload.uploadFile(file, '', parentFolderId, undefined, { + name: fileName, + nodeType: 'cm:content', + renditions: 'doclib' + }); + logger.info(`File uploaded successfully: ${fileName}`); + return result; + } catch (error) { + logger.error(`Failed to upload file: ${fileName}: ${error}`); + return Promise.reject(error); + } } async uploadFileWithRename( @@ -70,8 +77,11 @@ export class FileActionsApi { }; try { - return this.apiService.upload.uploadFile(file, '', parentId, nodeProps, opts); + const result = await this.apiService.upload.uploadFile(file, '', parentId, nodeProps, opts); + logger.info(`File uploaded successfully: ${newName}`); + return result; } catch (error) { + logger.error(`Failed to upload file: ${newName}: ${error}`); return Promise.reject(error); } } @@ -95,7 +105,7 @@ export class FileActionsApi { async getNodeProperty(nodeId: string, property: string): Promise { try { const node = await this.getNodeById(nodeId); - return node.entry.properties?.[property] || ''; + return node?.entry?.properties?.[property] || ''; } catch { return ''; } @@ -133,7 +143,7 @@ export class FileActionsApi { private async queryNodesNames(searchTerm: string): Promise { const data = { query: { - query: `cm:name:\"${searchTerm}*\"`, + query: `cm:name:"${searchTerm}*"`, language: 'afts' }, filterQueries: [{ query: `+TYPE:'cm:folder' OR +TYPE:'cm:content'` }] @@ -147,11 +157,17 @@ export class FileActionsApi { } async waitForNodes(searchTerm: string, data: { expect: number }): Promise { + logger.info(`waitForNodes: Waiting for ${data.expect} node(s) matching "${searchTerm}"`); const predicate = (totalItems: number) => totalItems === data.expect; + let pollCount = 0; const apiCall = async () => { try { - return (await this.queryNodesNames(searchTerm)).list.pagination.totalItems; + const totalItems = (await this.queryNodesNames(searchTerm)).list?.pagination?.totalItems || 0; + if (pollCount++ % 4 === 0) { + logger.info(`waitForNodes: "${searchTerm}" — found ${totalItems}, expecting ${data.expect}`); + } + return totalItems; } catch (error) { return 0; } @@ -208,7 +224,7 @@ export class FileActionsApi { const apiCall = async (): Promise => { try { - return (await this.queryNodesSearchHighlight(searchTerm)).list.pagination.totalItems; + return (await this.queryNodesSearchHighlight(searchTerm)).list?.pagination?.totalItems || 0; } catch (error) { logger.warn(`queryNodesSearchHighlight failed for "${searchTerm}": ${error}`); return 0; @@ -225,11 +241,13 @@ export class FileActionsApi { async updateNodeContent(nodeId: string, content: string, majorVersion: boolean = true, comment?: string, newName?: string): Promise { try { - const opts: { [key: string]: string | boolean } = { - majorVersion: majorVersion, - comment: comment, - name: newName - }; + const opts: { [key: string]: string | boolean } = { majorVersion }; + if (comment !== undefined) { + opts['comment'] = comment; + } + if (newName !== undefined) { + opts['name'] = newName; + } return await this.apiService.nodes.updateNodeContent(nodeId, content, opts); } catch (error) { logger.error(`${this.constructor.name} ${this.updateNodeContent.name}: ${error}`); diff --git a/projects/aca-playwright-shared/src/resources/test-files/file-pdf-with-jp2.pdf b/projects/aca-playwright-shared/src/resources/test-files/file-pdf-with-jp2.pdf new file mode 100644 index 000000000..37bcd5149 Binary files /dev/null and b/projects/aca-playwright-shared/src/resources/test-files/file-pdf-with-jp2.pdf differ diff --git a/projects/aca-playwright-shared/src/resources/test-files/index.ts b/projects/aca-playwright-shared/src/resources/test-files/index.ts index 03bddcd09..821e837b2 100644 --- a/projects/aca-playwright-shared/src/resources/test-files/index.ts +++ b/projects/aca-playwright-shared/src/resources/test-files/index.ts @@ -111,5 +111,10 @@ export const TEST_FILES = { AZW3_FILE: { path: resolve(__dirname, 'file-azw3.azw3'), name: 'file-azw3' + }, + PDF_JP2_FILE: { + path: resolve(__dirname, 'file-pdf-with-jp2.pdf'), + name: 'file-pdf-jp2', + data: 'Lorem ipsum dolor sit amet' } };