[ACS-8865] Viewer / DOCX files could not load preview for the first 20 seconds - error 409 for renditions (#10267)

* [ACS-8865] fix error 409 for viewer renditions

* [ACS-8865] unit tests

* [ACS-8865] unit test fix

* [ACS-8865] reduce duplication

* [ACS-8865] reduce duplication

* [ACS-8865] reduce duplication
This commit is contained in:
Mykyta Maliarchuk 2024-10-03 09:21:28 +02:00 committed by GitHub
parent 81fbaa4166
commit 0d79ff534c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 77 additions and 93 deletions

View File

@ -39,7 +39,7 @@ import { NodesApiService } from '../../common/services/nodes-api.service';
import { UploadService } from '../../common/services/upload.service'; import { UploadService } from '../../common/services/upload.service';
import { FileModel } from '../../common/models/file.model'; import { FileModel } from '../../common/models/file.model';
import { throwError } from 'rxjs'; import { throwError } from 'rxjs';
import { Component } from '@angular/core'; import { Component, SimpleChange, SimpleChanges } from '@angular/core';
import { ESCAPE } from '@angular/cdk/keycodes'; import { ESCAPE } from '@angular/cdk/keycodes';
import { By } from '@angular/platform-browser'; import { By } from '@angular/platform-browser';
import { MatIconModule } from '@angular/material/icon'; import { MatIconModule } from '@angular/material/icon';
@ -147,6 +147,21 @@ class ViewerWithCustomOpenWithComponent {}
}) })
class ViewerWithCustomMoreActionsComponent {} class ViewerWithCustomMoreActionsComponent {}
const getSimpleChanges = (currentValue: string, previousValue?: string): SimpleChanges => ({
nodeId: new SimpleChange(previousValue || null, currentValue, false)
});
const verifyCustomElement = (component: any, selector: string, done: DoneFn) => {
const customFixture = TestBed.createComponent(component);
const customElement: HTMLElement = customFixture.nativeElement;
customFixture.detectChanges();
customFixture.whenStable().then(() => {
expect(customElement.querySelector(selector)).toBeDefined();
done();
});
};
describe('AlfrescoViewerComponent', () => { describe('AlfrescoViewerComponent', () => {
let component: AlfrescoViewerComponent; let component: AlfrescoViewerComponent;
let fixture: ComponentFixture<AlfrescoViewerComponent>; let fixture: ComponentFixture<AlfrescoViewerComponent>;
@ -225,7 +240,7 @@ describe('AlfrescoViewerComponent', () => {
spyOn(component.nodesApi, 'getNode').and.callFake(() => Promise.resolve(new NodeEntry({ entry: new Node() }))); spyOn(component.nodesApi, 'getNode').and.callFake(() => Promise.resolve(new NodeEntry({ entry: new Node() })));
component.nodeId = '37f7f34d-4e64-4db6-bb3f-5c89f7844251'; component.nodeId = '37f7f34d-4e64-4db6-bb3f-5c89f7844251';
component.ngOnChanges(); component.ngOnChanges(getSimpleChanges('new-node-id'));
fixture.detectChanges(); fixture.detectChanges();
tick(100); tick(100);
@ -249,7 +264,7 @@ describe('AlfrescoViewerComponent', () => {
spyOn(component['contentApi'], 'getContentUrl').and.returnValue(contentUrl); spyOn(component['contentApi'], 'getContentUrl').and.returnValue(contentUrl);
component.ngOnChanges(); component.ngOnChanges({});
fixture.whenStable().then(() => { fixture.whenStable().then(() => {
fixture.detectChanges(); fixture.detectChanges();
expect(element.querySelector('adf-viewer-unknown-format')).toBeDefined(); expect(element.querySelector('adf-viewer-unknown-format')).toBeDefined();
@ -267,16 +282,28 @@ describe('AlfrescoViewerComponent', () => {
component.showViewer = true; component.showViewer = true;
component.nodeId = 'id1'; component.nodeId = 'id1';
component.ngOnChanges(); component.ngOnChanges(getSimpleChanges('id1'));
tick(); tick();
expect(component.fileName).toBe('file1'); expect(component.fileName).toBe('file1');
component.nodeId = 'id2'; component.nodeId = 'id2';
component.ngOnChanges(); component.ngOnChanges(getSimpleChanges('id2'));
tick(); tick();
expect(component.fileName).toBe('file2'); expect(component.fileName).toBe('file2');
expect(component['nodesApi'].getNode).toHaveBeenCalledTimes(2);
}));
it('should not setup the node twice if the node id is not changed', fakeAsync(() => {
spyOn(component['nodesApi'], 'getNode').and.stub();
component.showViewer = true;
component.nodeId = 'id1';
component.ngOnChanges(getSimpleChanges('id0', 'id1'));
tick();
component.ngOnChanges(getSimpleChanges('id1', 'id1'));
tick();
expect(component['nodesApi'].getNode).toHaveBeenCalledTimes(1);
})); }));
it('should append version of the file to the file content URL', fakeAsync(() => { it('should append version of the file to the file content URL', fakeAsync(() => {
@ -296,7 +323,7 @@ describe('AlfrescoViewerComponent', () => {
component.nodeId = 'id1'; component.nodeId = 'id1';
component.showViewer = true; component.showViewer = true;
component.versionId = null; component.versionId = null;
component.ngOnChanges(); component.ngOnChanges(getSimpleChanges('id1'));
tick(); tick();
expect(component.fileName).toBe('file1.pdf'); expect(component.fileName).toBe('file1.pdf');
@ -316,13 +343,13 @@ describe('AlfrescoViewerComponent', () => {
component.nodeId = 'id1'; component.nodeId = 'id1';
component.showViewer = true; component.showViewer = true;
component.versionId = '1.0'; component.versionId = '1.0';
component.ngOnChanges(); component.ngOnChanges(getSimpleChanges('id1'));
tick(); tick();
expect(component.fileName).toBe('file1'); expect(component.fileName).toBe('file1');
component.versionId = '1.1'; component.versionId = '1.1';
component.ngOnChanges(); component.ngOnChanges(getSimpleChanges('id1'));
tick(); tick();
expect(component.fileName).toBe('file2'); expect(component.fileName).toBe('file2');
@ -339,61 +366,23 @@ describe('AlfrescoViewerComponent', () => {
describe('Viewer Example Component Rendering', () => { describe('Viewer Example Component Rendering', () => {
it('should use custom toolbar', (done) => { it('should use custom toolbar', (done) => {
const customFixture = TestBed.createComponent(ViewerWithCustomToolbarComponent); verifyCustomElement(ViewerWithCustomToolbarComponent, '.custom-toolbar-element', done);
const customElement: HTMLElement = customFixture.nativeElement;
customFixture.detectChanges();
fixture.whenStable().then(() => {
expect(customElement.querySelector('.custom-toolbar-element')).toBeDefined();
done();
});
}); });
it('should use custom toolbar actions', (done) => { it('should use custom toolbar actions', (done) => {
const customFixture = TestBed.createComponent(ViewerWithCustomToolbarActionsComponent); verifyCustomElement(ViewerWithCustomToolbarActionsComponent, '#custom-button', done);
const customElement: HTMLElement = customFixture.nativeElement;
customFixture.detectChanges();
fixture.whenStable().then(() => {
expect(customElement.querySelector('#custom-button')).toBeDefined();
done();
});
}); });
it('should use custom info drawer', (done) => { it('should use custom info drawer', (done) => {
const customFixture = TestBed.createComponent(ViewerWithCustomSidebarComponent); verifyCustomElement(ViewerWithCustomSidebarComponent, '.custom-info-drawer-element', done);
const customElement: HTMLElement = customFixture.nativeElement;
customFixture.detectChanges();
fixture.whenStable().then(() => {
expect(customElement.querySelector('.custom-info-drawer-element')).toBeDefined();
done();
});
}); });
it('should use custom open with menu', (done) => { it('should use custom open with menu', (done) => {
const customFixture = TestBed.createComponent(ViewerWithCustomOpenWithComponent); verifyCustomElement(ViewerWithCustomOpenWithComponent, '.adf-viewer-container-open-with', done);
const customElement: HTMLElement = customFixture.nativeElement;
customFixture.detectChanges();
fixture.whenStable().then(() => {
expect(customElement.querySelector('.adf-viewer-container-open-with')).toBeDefined();
done();
});
}); });
it('should use custom more actions menu', (done) => { it('should use custom more actions menu', (done) => {
const customFixture = TestBed.createComponent(ViewerWithCustomMoreActionsComponent); verifyCustomElement(ViewerWithCustomMoreActionsComponent, '.adf-viewer-container-more-actions', done);
const customElement: HTMLElement = customFixture.nativeElement;
customFixture.detectChanges();
fixture.whenStable().then(() => {
expect(customElement.querySelector('.adf-viewer-container-more-actions')).toBeDefined();
done();
});
}); });
it('should stop propagation on sidebar keydown event [keydown]', async () => { it('should stop propagation on sidebar keydown event [keydown]', async () => {
@ -438,7 +427,7 @@ describe('AlfrescoViewerComponent', () => {
component.nodeId = 'the-node-id-of-the-file-to-preview'; component.nodeId = 'the-node-id-of-the-file-to-preview';
component.mimeType = null; component.mimeType = null;
component.ngOnChanges(); component.ngOnChanges(getSimpleChanges('id1'));
fixture.whenStable().then(() => { fixture.whenStable().then(() => {
fixture.detectChanges(); fixture.detectChanges();
expect(element.querySelector('adf-viewer-unknown-format')).not.toBeNull(); expect(element.querySelector('adf-viewer-unknown-format')).not.toBeNull();
@ -453,7 +442,7 @@ describe('AlfrescoViewerComponent', () => {
component.mimeType = null; component.mimeType = null;
component.nodeId = null; component.nodeId = null;
component.ngOnChanges(); component.ngOnChanges({});
fixture.whenStable().then(() => { fixture.whenStable().then(() => {
fixture.detectChanges(); fixture.detectChanges();
expect(element.querySelector('adf-viewer-unknown-format')).not.toBeNull(); expect(element.querySelector('adf-viewer-unknown-format')).not.toBeNull();
@ -472,9 +461,8 @@ describe('AlfrescoViewerComponent', () => {
expect(emittedValue).toBeUndefined(); expect(emittedValue).toBeUndefined();
}); });
component.ngOnChanges(); component.ngOnChanges({});
})); }));
//
}); });
describe('mimeType', () => { describe('mimeType', () => {
@ -684,7 +672,7 @@ describe('AlfrescoViewerComponent', () => {
spyOn(component['nodesApi'], 'getNode').and.returnValue(Promise.resolve(node)); spyOn(component['nodesApi'], 'getNode').and.returnValue(Promise.resolve(node));
spyOn(component['contentApi'], 'getContentUrl').and.returnValue(contentUrl); spyOn(component['contentApi'], 'getContentUrl').and.returnValue(contentUrl);
component.ngOnChanges(); component.ngOnChanges(getSimpleChanges('id1'));
fixture.whenStable().then(() => { fixture.whenStable().then(() => {
fixture.detectChanges(); fixture.detectChanges();
expect(component.nodeEntry).toBe(node); expect(component.nodeEntry).toBe(node);
@ -708,7 +696,7 @@ describe('AlfrescoViewerComponent', () => {
component.sharedLinkId = 'the-Shared-Link-id'; component.sharedLinkId = 'the-Shared-Link-id';
component.mimeType = null; component.mimeType = null;
component.ngOnChanges(); component.ngOnChanges({});
fixture.whenStable().then(() => { fixture.whenStable().then(() => {
fixture.detectChanges(); fixture.detectChanges();
expect(element.querySelector('[data-automation-id="adf-toolbar-left-back"]')).toBeNull(); expect(element.querySelector('[data-automation-id="adf-toolbar-left-back"]')).toBeNull();
@ -726,52 +714,47 @@ describe('AlfrescoViewerComponent', () => {
}); });
describe('SideBar Test', () => { describe('SideBar Test', () => {
it('should NOT display sidebar if is not allowed', (done) => { const verifySidebarDisplay = (
component.showRightSidebar = true; sidebarId: string,
component.allowRightSidebar = false; showSidebar: boolean,
allowSidebar: boolean,
expectedOrder: string | null,
done: DoneFn
) => {
if (sidebarId === '#adf-right-sidebar') {
component.showRightSidebar = showSidebar;
component.allowRightSidebar = allowSidebar;
} else if (sidebarId === '#adf-left-sidebar') {
component.showLeftSidebar = showSidebar;
component.allowLeftSidebar = allowSidebar;
}
fixture.detectChanges(); fixture.detectChanges();
fixture.whenStable().then(() => { fixture.whenStable().then(() => {
const sidebar = element.querySelector('#adf-right-sidebar'); const sidebar = element.querySelector(sidebarId);
expect(sidebar).toBeNull(); if (expectedOrder === null) {
expect(sidebar).toBeNull();
} else {
expect(getComputedStyle(sidebar).order).toEqual(expectedOrder);
}
done(); done();
}); });
};
it('should NOT display sidebar if is not allowed', (done) => {
verifySidebarDisplay('#adf-right-sidebar', true, false, null, done);
}); });
it('should display sidebar on the right side', (done) => { it('should display sidebar on the right side', (done) => {
component.allowRightSidebar = true; verifySidebarDisplay('#adf-right-sidebar', true, true, '4', done);
component.showRightSidebar = true;
fixture.detectChanges();
fixture.whenStable().then(() => {
const sidebar = element.querySelector('#adf-right-sidebar');
expect(getComputedStyle(sidebar).order).toEqual('4');
done();
});
}); });
it('should NOT display left sidebar if is not allowed', (done) => { it('should NOT display left sidebar if is not allowed', (done) => {
component.showLeftSidebar = true; verifySidebarDisplay('#adf-left-sidebar', true, false, null, done);
component.allowLeftSidebar = false;
fixture.detectChanges();
fixture.whenStable().then(() => {
const sidebar = element.querySelector('#adf-left-sidebar');
expect(sidebar).toBeNull();
done();
});
}); });
it('should display sidebar on the left side', (done) => { it('should display sidebar on the left side', (done) => {
component.allowLeftSidebar = true; verifySidebarDisplay('#adf-left-sidebar', true, true, '1', done);
component.showLeftSidebar = true;
fixture.detectChanges();
fixture.whenStable().then(() => {
const sidebar = element.querySelector('#adf-left-sidebar');
expect(getComputedStyle(sidebar).order).toEqual('1');
done();
});
}); });
}); });
@ -791,7 +774,7 @@ describe('AlfrescoViewerComponent', () => {
}); });
it('should Name File be present if is overlay mode ', async () => { it('should Name File be present if is overlay mode ', async () => {
component.ngOnChanges(); component.ngOnChanges({});
fixture.detectChanges(); fixture.detectChanges();
await fixture.whenStable(); await fixture.whenStable();
fixture.detectChanges(); fixture.detectChanges();
@ -870,7 +853,7 @@ describe('AlfrescoViewerComponent', () => {
component.nodeId = 'file-node-id'; component.nodeId = 'file-node-id';
spyOn(component.nodesApi, 'getNode').and.callFake(() => Promise.resolve(new NodeEntry({ entry: new Node() }))); spyOn(component.nodesApi, 'getNode').and.callFake(() => Promise.resolve(new NodeEntry({ entry: new Node() })));
expect(() => { expect(() => {
component.ngOnChanges(); component.ngOnChanges({});
}).not.toThrow(); }).not.toThrow();
}); });

View File

@ -25,6 +25,7 @@ import {
OnDestroy, OnDestroy,
OnInit, OnInit,
Output, Output,
SimpleChanges,
TemplateRef, TemplateRef,
ViewChild, ViewChild,
ViewEncapsulation ViewEncapsulation
@ -443,13 +444,13 @@ export class AlfrescoViewerComponent implements OnChanges, OnInit, OnDestroy {
return !!(this.nodeId || this.sharedLinkId); return !!(this.nodeId || this.sharedLinkId);
} }
ngOnChanges() { ngOnChanges(changes: SimpleChanges) {
if (this.showViewer) { if (this.showViewer) {
if (!this.isSourceDefined()) { if (!this.isSourceDefined()) {
throw new Error('A content source attribute value is missing.'); throw new Error('A content source attribute value is missing.');
} }
if (this.nodeId) { if (changes.nodeId?.currentValue !== changes.nodeId?.previousValue) {
this.setupNode(); this.setupNode();
} else if (this.sharedLinkId) { } else if (this.sharedLinkId) {
this.setupSharedLink(); this.setupSharedLink();