- +
- + { + + const loginPage = new LoginPage(); + const navigationBarPage = new NavigationBarPage(); + const formCloudDemoPage = new FormCloudDemoPage(); + const checkboxVisibilityFormJson = JSON.parse(checkboxVisibilityForm); + const widget = new Widget(); + + let tenantId, user; + let visibleCheckbox; + + const widgets = { + textOneId: 'textOne', + textTwoId: 'textTwo' + }; + + const value = { + displayCheckbox: 'showCheckbox', + notDisplayCheckbox: 'anythingElse' + }; + + const checkbox = { + checkboxFieldValue : 'CheckboxFieldValue', + checkboxVariableField: 'CheckboxVariableField', + checkboxFieldVariable: 'CheckboxFieldVariable', + checkboxFieldField: 'CheckboxFieldField', + checkboxVariableValue: 'CheckboxVariableValue', + checkboxVariableVariable: 'CheckboxVariableVariable' + }; + + beforeAll(async (done) => { + this.alfrescoJsApi = new AlfrescoApi({ + provider: 'BPM', + hostBpm: browser.params.testConfig.adf.url + }); + + const users = new UsersActions(); + + await this.alfrescoJsApi.login(browser.params.testConfig.adf.adminEmail, browser.params.testConfig.adf.adminPassword); + + user = await users.createTenantAndUser(this.alfrescoJsApi); + + tenantId = user.tenantId; + + await this.alfrescoJsApi.login(user.email, user.password); + + await loginPage.loginToProcessServicesUsingUserModel(user); + + navigationBarPage.clickFormCloudButton(); + + formCloudDemoPage.setConfigToEditor(checkboxVisibilityFormJson); + + done(); + }); + + afterAll(async (done) => { + await this.alfrescoJsApi.login(browser.params.testConfig.adf.adminEmail, browser.params.testConfig.adf.adminPassword); + await this.alfrescoJsApi.activiti.adminTenantsApi.deleteTenant(tenantId); + done(); + }); + + it('[C309647] Should be able to see Checkbox widget when visibility condition refers to another field with specific value', () => { + + widget.textWidget().isWidgetVisible(widgets.textOneId); + widget.checkboxWidget().isCheckboxHidden(checkbox.checkboxFieldValue); + widget.textWidget().setValue(widgets.textOneId, value.displayCheckbox); + widget.checkboxWidget().isCheckboxDisplayed(checkbox.checkboxFieldValue); + + widget.textWidget().setValue(widgets.textOneId, value.notDisplayCheckbox); + widget.checkboxWidget().isCheckboxHidden(checkbox.checkboxFieldValue); + }); + + it('[C309648] Should be able to see Checkbox widget when visibility condition refers to a form variable and a field', () => { + + widget.textWidget().isWidgetVisible(widgets.textOneId); + widget.checkboxWidget().isCheckboxHidden(checkbox.checkboxVariableField); + + widget.textWidget().setValue(widgets.textOneId, value.displayCheckbox); + widget.checkboxWidget().isCheckboxDisplayed(checkbox.checkboxVariableField); + + widget.textWidget().setValue(widgets.textOneId, value.notDisplayCheckbox); + widget.checkboxWidget().isCheckboxHidden(checkbox.checkboxVariableField); + }); + + it('[C309649] Should be able to see Checkbox widget when visibility condition refers to a field and a form variable', () => { + + widget.textWidget().isWidgetVisible(widgets.textOneId); + widget.checkboxWidget().isCheckboxHidden(checkbox.checkboxFieldVariable); + + widget.textWidget().setValue(widgets.textOneId, value.displayCheckbox); + expect(widget.checkboxWidget().isCheckboxDisplayed(checkbox.checkboxFieldVariable)).toBe(true); + + widget.textWidget().setValue(widgets.textOneId, value.notDisplayCheckbox); + widget.checkboxWidget().isCheckboxHidden(checkbox.checkboxFieldVariable); + }); + + it('[C311425] Should be able to see Checkbox widget when visibility condition refers to a field and another field', () => { + + widget.textWidget().isWidgetVisible(widgets.textOneId); + widget.textWidget().isWidgetVisible(widgets.textTwoId); + widget.checkboxWidget().isCheckboxHidden(checkbox.checkboxFieldField); + + widget.textWidget().setValue(widgets.textOneId, value.displayCheckbox); + widget.checkboxWidget().isCheckboxHidden(checkbox.checkboxFieldField); + + widget.textWidget().setValue(widgets.textTwoId, value.displayCheckbox); + widget.checkboxWidget().isCheckboxDisplayed(checkbox.checkboxFieldField); + + widget.textWidget().setValue(widgets.textOneId, value.notDisplayCheckbox); + widget.checkboxWidget().isCheckboxHidden(checkbox.checkboxFieldField); + }); + + it('[C311424] Should be able to see Checkbox widget when visibility condition refers to a variable with specific value', () => { + formCloudDemoPage.setConfigToEditor(checkboxVisibilityFormJson); + + widget.checkboxWidget().isCheckboxDisplayed(checkbox.checkboxVariableValue); + + visibleCheckbox = checkboxVisibilityFormJson; + visibleCheckbox.formRepresentation.formDefinition.variables[0].value = value.notDisplayCheckbox; + formCloudDemoPage.setConfigToEditor(visibleCheckbox); + + widget.checkboxWidget().isCheckboxHidden(checkbox.checkboxVariableValue); + + visibleCheckbox = checkboxVisibilityFormJson; + visibleCheckbox.formRepresentation.formDefinition.variables[0].value = value.displayCheckbox; + formCloudDemoPage.setConfigToEditor(visibleCheckbox); + }); + + it('[C311426] Should be able to see Checkbox widget when visibility condition refers to form variable and another form variable', () => { + formCloudDemoPage.setConfigToEditor(checkboxVisibilityFormJson); + + widget.checkboxWidget().isCheckboxDisplayed(checkbox.checkboxVariableVariable); + + visibleCheckbox = checkboxVisibilityFormJson; + visibleCheckbox.formRepresentation.formDefinition.variables[0].value = value.notDisplayCheckbox; + formCloudDemoPage.setConfigToEditor(visibleCheckbox); + + widget.checkboxWidget().isCheckboxHidden(checkbox.checkboxVariableVariable); + + visibleCheckbox = checkboxVisibilityFormJson; + visibleCheckbox.formRepresentation.formDefinition.variables[1].value = value.notDisplayCheckbox; + formCloudDemoPage.setConfigToEditor(visibleCheckbox); + + widget.checkboxWidget().isCheckboxDisplayed(checkbox.checkboxVariableVariable); + + visibleCheckbox = checkboxVisibilityFormJson; + visibleCheckbox.formRepresentation.formDefinition.variables[0].value = value.displayCheckbox; + visibleCheckbox.formRepresentation.formDefinition.variables[1].value = value.displayCheckbox; + formCloudDemoPage.setConfigToEditor(visibleCheckbox); + }); +}); diff --git a/e2e/pages/adf/configEditorPage.ts b/e2e/pages/adf/configEditorPage.ts index 7e4f8c7277..f6738fd142 100644 --- a/e2e/pages/adf/configEditorPage.ts +++ b/e2e/pages/adf/configEditorPage.ts @@ -15,25 +15,35 @@ * limitations under the License. */ -import { element, by } from 'protractor'; +import { element, by, browser } from 'protractor'; import { BrowserVisibility, BrowserActions } from '@alfresco/adf-testing'; export class ConfigEditorPage { + textField = element(by.css('#adf-form-config-editor div.overflow-guard > textarea')); + enterConfiguration(text) { - const textField = element(by.css('#adf-code-configuration-editor div.overflow-guard > textarea')); - BrowserVisibility.waitUntilElementIsVisible(textField); - textField.sendKeys(text); + + BrowserVisibility.waitUntilElementIsVisible(this.textField); + this.textField.sendKeys(text); return this; } clickSaveButton() { - const saveButton = element(by.id('adf-configuration-save')); + const saveButton = element(by.id('adf-form-config-save')); BrowserActions.click(saveButton); } clickClearButton() { - const clearButton = element(by.id('adf-configuration-clear')); + BrowserVisibility.waitUntilElementIsVisible(this.textField); + const clearButton = element(by.id('adf-form-config-clear')); BrowserActions.click(clearButton); } + + enterBulkConfiguration(text) { + this.clickClearButton(); + BrowserVisibility.waitUntilElementIsVisible(this.textField); + browser.executeScript('this.monaco.editor.getModels()[0].setValue(`' + JSON.stringify(text) + '`)'); + this.clickSaveButton(); + } } diff --git a/e2e/pages/adf/demo-shell/process-services-cloud/cloudFormDemoPage.ts b/e2e/pages/adf/demo-shell/process-services-cloud/cloudFormDemoPage.ts new file mode 100644 index 0000000000..4ea9a77c2f --- /dev/null +++ b/e2e/pages/adf/demo-shell/process-services-cloud/cloudFormDemoPage.ts @@ -0,0 +1,46 @@ +/*! + * @license + * Copyright 2019 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ConfigEditorPage } from '../../configEditorPage'; +import { BrowserVisibility } from '@alfresco/adf-testing'; +import { by, element, browser } from 'protractor'; + +export class FormCloudDemoPage { + + formCloudEditor = element.all(by.css('.mat-tab-list .mat-tab-label')).get(1); + formCloudRender = element.all(by.css('.mat-tab-list .mat-tab-label')).get(0); + + configEditorPage = new ConfigEditorPage(); + + goToEditor() { + BrowserVisibility.waitUntilElementIsVisible(this.formCloudEditor); + this.formCloudEditor.click(); + } + + goToRenderedForm() { + BrowserVisibility.waitUntilElementIsVisible(this.formCloudRender); + this.formCloudRender.click(); + } + + setConfigToEditor(text) { + this.goToEditor(); + browser.sleep(2000); + this.configEditorPage.enterBulkConfiguration(text); + this.goToRenderedForm(); + browser.sleep(2000); + } +} diff --git a/e2e/pages/adf/navigationBarPage.ts b/e2e/pages/adf/navigationBarPage.ts index c6450de776..bd345afea7 100644 --- a/e2e/pages/adf/navigationBarPage.ts +++ b/e2e/pages/adf/navigationBarPage.ts @@ -205,6 +205,11 @@ export class NavigationBarPage { BrowserActions.click(this.formButton); } + clickFormCloudButton() { + this.clickMenuButton('Process Cloud'); + BrowserActions.click(this.formButton); + } + checkLogoTooltip(logoTooltipTitle) { const logoTooltip = element(by.css('a[title="' + logoTooltipTitle + '"]')); BrowserVisibility.waitUntilElementIsVisible(logoTooltip); diff --git a/e2e/resources/forms/checkbox-visibility-condition.ts b/e2e/resources/forms/checkbox-visibility-condition.ts new file mode 100644 index 0000000000..91c8cc2f16 --- /dev/null +++ b/e2e/resources/forms/checkbox-visibility-condition.ts @@ -0,0 +1,222 @@ +/*! + * @license + * Copyright 2019 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /* tslint:disable */ +export const checkboxVisibilityForm = `{ + "formRepresentation": { + "id": "form-412cdeab-de90-4099-875f-676366e48fc9", + "name": "test", + "description": "", + "version": 0, + "formDefinition": { + "tabs": [], + "fields": [ + { + "id": "85a4f564-2c70-438a-ae0f-b9c8af4887c2", + "name": "Label", + "type": "container", + "tab": null, + "numberOfColumns": 2, + "fields": { + "1": [ + { + "id": "CheckboxFieldField", + "name": "CheckboxFieldField", + "type": "boolean", + "required": false, + "colspan": 1, + "visibilityCondition": { + "leftFormFieldId": "textOne", + "leftRestResponseId": "", + "operator": "==", + "rightValue": "", + "rightType": null, + "rightFormFieldId": "textTwo", + "rightRestResponseId": "", + "nextConditionOperator": "" + }, + "params": { + "existingColspan": 1, + "maxColspan": 2 + } + }, + { + "id": "CheckboxFieldVariable", + "name": "CheckboxFieldVariable", + "type": "boolean", + "required": false, + "colspan": 1, + "visibilityCondition": { + "leftFormFieldId": "textOne", + "leftRestResponseId": "", + "operator": "==", + "rightValue": "", + "rightType": null, + "rightFormFieldId": "", + "rightRestResponseId": "cbc51284-04c4-462f-ab72-2b9f8b14907b", + "nextConditionOperator": "" + }, + "params": { + "existingColspan": 1, + "maxColspan": 2 + } + }, + { + "id": "CheckboxFieldValue", + "name": "CheckboxFieldValue", + "type": "boolean", + "required": false, + "colspan": 1, + "visibilityCondition": { + "leftFormFieldId": "textOne", + "leftRestResponseId": "", + "operator": "==", + "rightValue": "showCheckbox", + "rightType": null, + "rightFormFieldId": "", + "rightRestResponseId": "", + "nextConditionOperator": "", + "nextCondition": null + }, + "params": { + "existingColspan": 1, + "maxColspan": 2 + } + }, + { + "id": "CheckboxVariableValue", + "name": "CheckboxVariableValue", + "type": "boolean", + "required": false, + "colspan": 1, + "visibilityCondition": { + "leftFormFieldId": "", + "leftRestResponseId": "cbc51284-04c4-462f-ab72-2b9f8b14907b", + "operator": "==", + "rightValue": "showCheckbox", + "rightType": null, + "rightFormFieldId": "", + "rightRestResponseId": "", + "nextConditionOperator": "", + "nextCondition": null + }, + "params": { + "existingColspan": 1, + "maxColspan": 2 + } + }, + { + "id": "CheckboxVariableVariable", + "name": "CheckboxVariableVariable", + "type": "boolean", + "required": false, + "colspan": 1, + "visibilityCondition": { + "leftFormFieldId": "", + "leftRestResponseId": "cbc51284-04c4-462f-ab72-2b9f8b14907b", + "operator": "==", + "rightValue": "", + "rightType": null, + "rightFormFieldId": "", + "rightRestResponseId": "87df371a-4238-43f8-92e5-ef3f6a19f379", + "nextConditionOperator": "", + "nextCondition": null + }, + "params": { + "existingColspan": 1, + "maxColspan": 2 + } + }, + { + "id": "CheckboxVariableField", + "name": "CheckboxVariableField", + "type": "boolean", + "required": false, + "colspan": 1, + "visibilityCondition": { + "leftFormFieldId": "", + "leftRestResponseId": "cbc51284-04c4-462f-ab72-2b9f8b14907b", + "operator": "==", + "rightValue": "", + "rightType": null, + "rightFormFieldId": "textOne", + "rightRestResponseId": "", + "nextConditionOperator": "", + "nextCondition": null + }, + "params": { + "existingColspan": 1, + "maxColspan": 2 + } + } + ], + "2": [ + { + "id": "textOne", + "name": "textOne", + "type": "text", + "required": false, + "colspan": 1, + "placeholder": null, + "minLength": 0, + "maxLength": 0, + "regexPattern": null, + "visibilityCondition": null, + "params": { + "existingColspan": 1, + "maxColspan": 2 + } + }, + { + "id": "textTwo", + "name": "textTwo", + "type": "text", + "required": false, + "colspan": 1, + "placeholder": null, + "minLength": 0, + "maxLength": 0, + "regexPattern": null, + "visibilityCondition": null, + "params": { + "existingColspan": 1, + "maxColspan": 2 + } + } + ] + } + } + ], + "outcomes": [], + "metadata": {}, + "variables": [ + { + "id": "cbc51284-04c4-462f-ab72-2b9f8b14907b", + "name": "varString1", + "type": "string", + "value": "showCheckbox" + }, + { + "id": "87df371a-4238-43f8-92e5-ef3f6a19f379", + "name": "varString2", + "type": "string", + "value": "showCheckbox" + } + ] + } + } +}`; diff --git a/lib/testing/src/lib/core/pages/form/formFields.ts b/lib/testing/src/lib/core/pages/form/formFields.ts index c9f70f907a..006b1b78d7 100644 --- a/lib/testing/src/lib/core/pages/form/formFields.ts +++ b/lib/testing/src/lib/core/pages/form/formFields.ts @@ -42,7 +42,7 @@ export class FormFields { checkWidgetIsVisible(fieldId) { const fieldElement = element.all(by.css(`adf-form-field div[id='field-${fieldId}-container']`)).first(); - BrowserVisibility.waitUntilElementIsVisible(fieldElement); + BrowserVisibility.waitUntilElementIsOnPage(fieldElement); } checkWidgetIsHidden(fieldId) { @@ -50,6 +50,12 @@ export class FormFields { BrowserVisibility.waitUntilElementIsVisible(hiddenElement); } + checkWidgetIsNotHidden(fieldId) { + this.checkWidgetIsVisible(fieldId); + const hiddenElement = element(by.css(`adf-form-field div[id='field-${fieldId}-container'][hidden]`)); + return BrowserVisibility.waitUntilElementIsNotVisible(hiddenElement, 6000); + } + getWidget(fieldId) { const widget = element(by.css(`adf-form-field div[id='field-${fieldId}-container']`)); BrowserVisibility.waitUntilElementIsVisible(widget); diff --git a/lib/testing/src/lib/core/pages/form/widgets/checkboxWidget.ts b/lib/testing/src/lib/core/pages/form/widgets/checkboxWidget.ts index 72260387a1..582412ba9f 100644 --- a/lib/testing/src/lib/core/pages/form/widgets/checkboxWidget.ts +++ b/lib/testing/src/lib/core/pages/form/widgets/checkboxWidget.ts @@ -34,7 +34,7 @@ export class CheckboxWidget { } isCheckboxDisplayed(fieldId) { - return this.formFields.checkWidgetIsVisible(fieldId); + return this.formFields.checkWidgetIsNotHidden(fieldId); } isCheckboxHidden(fieldId) { From 028916e3868d46fe12910d4b0aec7e08bce367fd Mon Sep 17 00:00:00 2001 From: Eugenio Romano Date: Mon, 1 Jul 2019 11:35:27 +0100 Subject: [PATCH 024/140] Fix user info unit test (#4887) * fix unit test user info component * fix unit test user info component * replace download call with spy * fix karma conf --- lib/core/dialogs/download-zip.dialog.spec.ts | 42 +++++++++++++------ lib/core/karma.conf.js | 6 +++ .../components/user-info.component.spec.ts | 21 +++++----- 3 files changed, 46 insertions(+), 23 deletions(-) diff --git a/lib/core/dialogs/download-zip.dialog.spec.ts b/lib/core/dialogs/download-zip.dialog.spec.ts index 0781fa8463..f21a588567 100755 --- a/lib/core/dialogs/download-zip.dialog.spec.ts +++ b/lib/core/dialogs/download-zip.dialog.spec.ts @@ -22,7 +22,7 @@ import { DownloadZipDialogComponent } from './download-zip.dialog'; import { setupTestBed } from '../testing/setupTestBed'; import { CoreTestingModule } from '../testing/core.testing.module'; import { DownloadZipService } from '../services/download-zip.service'; -import { of } from 'rxjs'; +import { Observable } from 'rxjs/index'; describe('DownloadZipDialogComponent', () => { @@ -40,17 +40,6 @@ describe('DownloadZipDialogComponent', () => { ] }; - const pendingDownloadEntry = { - entry: { - bytesAdded: 0, - filesAdded: 0, - id: '5bfb0907', - status: 'PENDING', - totalBytes: 0, - totalFiles: 0 - } - }; - setupTestBed({ imports: [CoreTestingModule], providers: [ @@ -101,6 +90,13 @@ describe('DownloadZipDialogComponent', () => { }); it('should call cancelDownload when CANCEL button is clicked', () => { + spyOn(downloadZipService, 'createDownload').and.callFake(() => { + return new Observable((observer) => { + observer.next(); + observer.complete(); + }); + }); + fixture.detectChanges(); spyOn(component, 'cancelDownload'); @@ -111,12 +107,25 @@ describe('DownloadZipDialogComponent', () => { }); it('should call createDownload when component is initialize', () => { - const createDownloadSpy = spyOn(downloadZipService, 'createDownload').and.returnValue(of(pendingDownloadEntry)); + const createDownloadSpy = spyOn(downloadZipService, 'createDownload').and.callFake(() => { + return new Observable((observer) => { + observer.next(); + observer.complete(); + }); + }); + fixture.detectChanges(); expect(createDownloadSpy).toHaveBeenCalled(); }); it('should close dialog when download is completed', () => { + spyOn(downloadZipService, 'createDownload').and.callFake(() => { + return new Observable((observer) => { + observer.next(); + observer.complete(); + }); + }); + component.download('fakeUrl', 'fileName'); spyOn(component, 'cancelDownload'); fixture.detectChanges(); @@ -124,6 +133,13 @@ describe('DownloadZipDialogComponent', () => { }); it('should close dialog when download is cancelled', () => { + spyOn(downloadZipService, 'createDownload').and.callFake(() => { + return new Observable((observer) => { + observer.next(); + observer.complete(); + }); + }); + fixture.detectChanges(); component.download('url', 'filename'); spyOn(downloadZipService, 'cancelDownload'); diff --git a/lib/core/karma.conf.js b/lib/core/karma.conf.js index 882b679916..a46e16d80e 100644 --- a/lib/core/karma.conf.js +++ b/lib/core/karma.conf.js @@ -12,8 +12,10 @@ module.exports = function (config) { {pattern: 'node_modules/hammerjs/hammer.min.js.map', included: false, watched: false}, // pdf-js + {pattern: 'node_modules/pdfjs-dist/build/pdf.js.map', included: false, watched: false}, {pattern: 'node_modules/pdfjs-dist/build/pdf.js', included: true, watched: false}, {pattern: 'node_modules/pdfjs-dist/build/pdf.worker.js', included: true, watched: false, served: true}, + {pattern: 'node_modules/pdfjs-dist/build/pdf.worker.js.map', included: false, watched: false}, {pattern: 'node_modules/pdfjs-dist/build/pdf.worker.min.js', included: true, watched: false, served: true}, {pattern: 'node_modules/pdfjs-dist/web/pdf_viewer.js', included: true, watched: false}, @@ -28,6 +30,7 @@ module.exports = function (config) { {pattern: 'lib/core/i18n/**/en.json', included: false, served: true, watched: false}, {pattern: 'lib/core/**/*.ts', included: false, served: true, watched: false}, {pattern: 'lib/core/assets/**/*.svg', included: false, served: true, watched: false}, + {pattern: 'lib/core/assets/**/*.png', included: false, served: true, watched: false}, {pattern: 'lib/config/app.config.json', included: false, served: true, watched: false}, {pattern: 'lib/core/viewer/assets/fake-test-file.pdf', included: false, served: true, watched: false}, {pattern: 'lib/core/viewer/assets/fake-test-file.txt', included: false, served: true, watched: false}, @@ -45,7 +48,10 @@ module.exports = function (config) { '/pdf.worker.min.js' :'/base/node_modules/pdfjs-dist/build/pdf.worker.min.js', '/pdf.worker.js' :'/base/node_modules/pdfjs-dist/build/pdf.worker.js', '/fake-url-file.png' :'/base/lib/core/assets/images/logo.png', + '/alfresco-logo.svg' :'/base/lib/core/assets/images/alfresco-logo.svg', '/assets/images/': '/base/lib/core/assets/images/', + '/assets/images/ecm-background.png': '/base/lib/core/assets/images/ecm-background.png', + '/assets/images/bpm-background.png': '/base/lib/core/assets/images/bpm-background.png', '/content.bin': '/base/lib/core/viewer/assets/fake-test-file.pdf', '/base/assets/' :'/base/lib/core/assets/', '/assets/adf-core/i18n/en.json': '/base/lib/core/i18n/en.json', diff --git a/lib/core/userinfo/components/user-info.component.spec.ts b/lib/core/userinfo/components/user-info.component.spec.ts index cb57d9e206..68eed47433 100644 --- a/lib/core/userinfo/components/user-info.component.spec.ts +++ b/lib/core/userinfo/components/user-info.component.spec.ts @@ -99,6 +99,9 @@ describe('User info component', () => { bpmUserService = TestBed.get(BpmUserService); contentService = TestBed.get(ContentService); identityUserService = TestBed.get(IdentityUserService); + + spyOn(bpmUserService, 'getCurrentUserProfileImage').and.returnValue(''); + spyOn(contentService, 'getContentUrl').and.returnValue('alfresco-logo.svg'); })); afterEach(() => { @@ -203,7 +206,6 @@ describe('User info component', () => { spyOn(authService, 'isEcmLoggedIn').and.returnValue(true); spyOn(authService, 'isLoggedIn').and.returnValue(true); spyOn(ecmUserService, 'getCurrentUserInfo').and.returnValue(of(fakeEcmUser)); - spyOn(contentService, 'getContentUrl').and.returnValue('assets/images/ecmImg.gif'); fixture.detectChanges(); })); @@ -217,7 +219,7 @@ describe('User info component', () => { expect(element.querySelector('#userinfo_container')).not.toBeNull(); expect(loggedImage).not.toBeNull(); - expect(loggedImage.properties.src).toContain('assets/images/ecmImg.gif'); + expect(loggedImage.properties.src).toContain('alfresco-logo.svg'); }); })); @@ -235,11 +237,11 @@ describe('User info component', () => { }); expect(element.querySelector('#userinfo_container')).not.toBeNull(); expect(loggedImage).not.toBeNull(); - expect(loggedImage.properties.src).toContain('assets/images/ecmImg.gif'); + expect(loggedImage.properties.src).toContain('alfresco-logo.svg'); }); })); - it('should get the ecm user informations from the service', async(() => { + it('should get the ecm user information from the service', async(() => { fixture.detectChanges(); fixture.whenStable().then(() => { fixture.detectChanges(); @@ -253,7 +255,7 @@ describe('User info component', () => { expect(element.querySelector('#userinfo_container')).not.toBeNull(); expect(fixture.debugElement.query(By.css('#ecm-username'))).not.toBeNull(); expect(ecmImage).not.toBeNull(); - expect(ecmImage.properties.src).toContain('assets/images/ecmImg.gif'); + expect(ecmImage.properties.src).toContain('alfresco-logo.svg'); expect(ecmFullName.nativeElement.textContent).toContain('fake-ecm-first-name fake-ecm-last-name'); expect(ecmJobTitle.nativeElement.textContent).toContain('USER_PROFILE.LABELS.ECM.JOB_TITLE'); }); @@ -436,7 +438,6 @@ describe('User info component', () => { spyOn(authService, 'isEcmLoggedIn').and.returnValue(true); spyOn(authService, 'isBpmLoggedIn').and.returnValue(true); spyOn(authService, 'isLoggedIn').and.returnValue(true); - spyOn(contentService, 'getContentUrl').and.returnValue('src/assets/images/ecmImg.gif'); ecmUserInfoSpy = spyOn(ecmUserService, 'getCurrentUserInfo').and.returnValue(of(fakeEcmUser)); spyOn(bpmUserService, 'getCurrentUserInfo').and.returnValue(of(fakeBpmUser)); @@ -468,7 +469,7 @@ describe('User info component', () => { }); })); - it('should get the bpm user informations from the service', async(() => { + it('should get the bpm user information from the service', async(() => { openUserInfo(); const bpmTab = fixture.debugElement.queryAll(By.css('#tab-group-env .mat-tab-labels .mat-tab-label'))[1]; bpmTab.triggerEventHandler('click', null); @@ -485,7 +486,7 @@ describe('User info component', () => { }); })); - it('should get the ecm user informations from the service', async(() => { + it('should get the ecm user information from the service', async(() => { openUserInfo(); const ecmUsername = fixture.debugElement.query(By.css('#ecm-username')); const ecmImage = fixture.debugElement.query(By.css('#ecm-user-detail-image')); @@ -495,7 +496,7 @@ describe('User info component', () => { expect(element.querySelector('#userinfo_container')).toBeDefined(); expect(ecmUsername).not.toBeNull(); expect(ecmImage).not.toBeNull(); - expect(ecmImage.properties.src).toContain('assets/images/ecmImg.gif'); + expect(ecmImage.properties.src).toContain('alfresco-logo.svg'); expect(fixture.debugElement.query(By.css('#ecm-full-name')).nativeElement.textContent).toContain('fake-ecm-first-name fake-ecm-last-name'); expect(fixture.debugElement.query(By.css('#ecm-job-title')).nativeElement.textContent).toContain('job-ecm-test'); }); @@ -505,7 +506,7 @@ describe('User info component', () => { openUserInfo(); expect(element.querySelector('#userinfo_container')).toBeDefined(); expect(element.querySelector('#logged-user-img')).toBeDefined(); - expect(element.querySelector('#logged-user-img').getAttribute('src')).toEqual('src/assets/images/ecmImg.gif'); + expect(element.querySelector('#logged-user-img').getAttribute('src')).toEqual('alfresco-logo.svg'); })); it('should show the ecm initials if the ecm user has no image', async(() => { From 87b80235a705ddcedb0224364b16c1aacdafee76 Mon Sep 17 00:00:00 2001 From: Suzana Dirla Date: Tue, 2 Jul 2019 14:07:15 +0300 Subject: [PATCH 025/140] [ADF-4701] Upgrade angular libs (#4877) * [ADF-4701] Upgrade angular material to 7.3.7 version * [ADF-4701] upgrade angular libs * [ADF-4701] upgrade angular libs * [ADF-4530] temporary disable test - will be fixed in a separate PR for https://issues.alfresco.com/jira/browse/ADF-4704 - the 'expected behavior' of the ADF-4530 corresponding bug is that should display 'all the available Process Definitions defined in the app' * e2e test does not need bpm user * e2e FIX waitUntilElementIsClickable * Revert "e2e test does not need bpm user" This reverts commit 9a5c4d4 - Travis seems to need initial code * e2e fix button selector - caused TimeoutError: Element is not Clickable * e2e scroll into view fix * e2e fixes scroll into view & selectors * e2e fixed close action menu - close menu with all disabled items fix - opened related issue https://issues.alfresco.com/jira/browse/ADF-4712 - checkContextActionIsVisible should check only visibility - all items might be disabled, so un-clickable - close menu changed bcs. overlay backdrop caused TimeoutError: Element is not Clickable * e2e disabled button is not supposed to be clickable - fixed TimeoutError: Element is not Clickable * e2e update messages * e2e check invisibilityOf item * e2e extra filter * e2e wait waitTillContentLoaded - created related issue https://issues.alfresco.com/jira/browse/ADF-4715 * [ADF-4715] a process never has CREATED status * [ADF-4717] wait for filtered content to be loaded - initiator filter must have 'username' value --- .../version/version-actions.e2e.ts | 6 +- .../version/version-permissions.e2e.ts | 2 +- .../version/version-properties.e2e.ts | 4 +- e2e/pages/adf/contentServicesPage.ts | 10 +- e2e/pages/adf/dialog/uploadToggles.ts | 5 +- e2e/pages/adf/versionManagerPage.ts | 11 +- e2e/pages/adf/viewerPage.ts | 4 + .../process-filter-results.e2e.ts | 59 ++- .../start-process-cloud.component.spec.ts | 5 +- lib/testing/src/lib/core/pages/header.page.ts | 5 +- .../src/lib/core/utils/browser-actions.ts | 5 + .../src/lib/core/utils/browser-visibility.ts | 26 +- .../start-process-cloud-component.page.ts | 1 - package-lock.json | 351 +++++++++++------- package.json | 30 +- 15 files changed, 305 insertions(+), 219 deletions(-) diff --git a/e2e/content-services/version/version-actions.e2e.ts b/e2e/content-services/version/version-actions.e2e.ts index 9c0010f86c..1d369300b5 100644 --- a/e2e/content-services/version/version-actions.e2e.ts +++ b/e2e/content-services/version/version-actions.e2e.ts @@ -90,14 +90,14 @@ describe('Version component actions', () => { it('[C280003] Should not be possible delete a file version if there is only one version', () => { versionManagePage.clickActionButton('1.0'); expect(element(by.css(`[id="adf-version-list-action-delete-1.0"]`)).isEnabled()).toBe(false); - versionManagePage.closeActionButton(); + versionManagePage.closeActionsMenu(); BrowserVisibility.waitUntilElementIsNotOnPage(element(by.css(`[id="adf-version-list-action-delete-1.0"]`))); }); it('[C280004] Should not be possible restore the version if there is only one version', () => { versionManagePage.clickActionButton('1.0'); expect(element(by.css(`[id="adf-version-list-action-restore-1.0"]`)).isEnabled()).toBe(false); - versionManagePage.closeActionButton(); + versionManagePage.closeActionsMenu(); BrowserVisibility.waitUntilElementIsNotOnPage(element(by.css(`[id="adf-version-list-action-restore-1.0"]`))); }); @@ -108,7 +108,7 @@ describe('Version component actions', () => { versionManagePage.clickActionButton('1.1').checkActionsArePresent('1.1'); - versionManagePage.closeActionButton(); + versionManagePage.closeActionsMenu(); }); it('[C269081] Should be possible download all the version of a file', () => { diff --git a/e2e/content-services/version/version-permissions.e2e.ts b/e2e/content-services/version/version-permissions.e2e.ts index c79735a9b5..eb0c73fd90 100644 --- a/e2e/content-services/version/version-permissions.e2e.ts +++ b/e2e/content-services/version/version-permissions.e2e.ts @@ -316,7 +316,7 @@ describe('Version component permissions', () => { expect(element(by.css(`[id="adf-version-list-action-delete-1.1"]`)).isEnabled()).toBe(false); - versionManagePage.closeActionButton(); + versionManagePage.closeActionsMenu(); versionManagePage.closeVersionDialog(); }); diff --git a/e2e/content-services/version/version-properties.e2e.ts b/e2e/content-services/version/version-properties.e2e.ts index 1b96137755..b46c10f4d0 100644 --- a/e2e/content-services/version/version-properties.e2e.ts +++ b/e2e/content-services/version/version-properties.e2e.ts @@ -79,7 +79,7 @@ describe('Version Properties', () => { BrowserVisibility.waitUntilElementIsNotVisible(element(by.css(`[id="adf-version-list-action-download-1.0"]`))); - versionManagePage.closeActionButton(); + versionManagePage.closeDisabledActionsMenu(); }); it('[C279992] Should be present the download action when allowDownload property is true', () => { @@ -89,7 +89,7 @@ describe('Version Properties', () => { BrowserVisibility.waitUntilElementIsVisible(element(by.css(`[id="adf-version-list-action-download-1.0"]`))); - versionManagePage.closeActionButton(); + versionManagePage.closeActionsMenu(); }); it('[C269085] Should show/hide comments when showComments true/false', () => { diff --git a/e2e/pages/adf/contentServicesPage.ts b/e2e/pages/adf/contentServicesPage.ts index bdbef37a1e..99504118cf 100644 --- a/e2e/pages/adf/contentServicesPage.ts +++ b/e2e/pages/adf/contentServicesPage.ts @@ -48,7 +48,8 @@ export class ContentServicesPage { createLibraryButton = element(by.css('button[data-automation-id="create-new-library"]')); activeBreadcrumb = element(by.css('div[class*="active"]')); tooltip = by.css('div[class*="--text adf-full-width"] span'); - uploadFileButton = element(by.css('input[data-automation-id="upload-single-file"]')); + uploadFileButton = element(by.css('.adf-upload-button-file-container button')); + uploadFileButtonInput = element(by.css('input[data-automation-id="upload-single-file"]')); uploadMultipleFileButton = element(by.css('input[data-automation-id="upload-multiple-files"]')); uploadFolderButton = element(by.css('input[data-automation-id="uploadFolder"]')); errorSnackBar = element(by.css('simple-snack-bar[class*="mat-simple-snackbar"]')); @@ -90,7 +91,6 @@ export class ContentServicesPage { checkContextActionIsVisible(actionName) { const actionButton = element(by.css(`button[data-automation-id="context-${actionName}"`)); BrowserVisibility.waitUntilElementIsVisible(actionButton); - BrowserVisibility.waitUntilElementIsClickable(actionButton); return actionButton; } @@ -178,6 +178,7 @@ export class ContentServicesPage { } disableDropFilesInAFolder() { + browser.executeScript('arguments[0].scrollIntoView()', this.multipleFileUploadToggle); this.formControllersPage.disableToggle(this.multipleFileUploadToggle); return this; } @@ -390,8 +391,7 @@ export class ContentServicesPage { uploadFile(fileLocation) { this.checkUploadButton(); - BrowserVisibility.waitUntilElementIsVisible(this.uploadFileButton); - this.uploadFileButton.sendKeys(path.resolve(path.join(browser.params.testConfig.main.rootPath, fileLocation))); + this.uploadFileButtonInput.sendKeys(path.resolve(path.join(browser.params.testConfig.main.rootPath, fileLocation))); this.checkUploadButton(); return this; } @@ -416,7 +416,7 @@ export class ContentServicesPage { getSingleFileButtonTooltip() { BrowserVisibility.waitUntilElementIsVisible(this.uploadFileButton); - return this.uploadFileButton.getAttribute('title'); + return this.uploadFileButtonInput.getAttribute('title'); } getMultipleFileButtonTooltip() { diff --git a/e2e/pages/adf/dialog/uploadToggles.ts b/e2e/pages/adf/dialog/uploadToggles.ts index 2fb2652516..7b01598a3b 100644 --- a/e2e/pages/adf/dialog/uploadToggles.ts +++ b/e2e/pages/adf/dialog/uploadToggles.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import { by, element, protractor } from 'protractor'; +import { browser, by, element, protractor } from 'protractor'; import { BrowserVisibility, FormControllersPage } from '@alfresco/adf-testing'; export class UploadToggles { @@ -31,6 +31,7 @@ export class UploadToggles { disableUploadCheckbox = element(by.css('[id="adf-disable-upload"]')); enableMultipleFileUpload() { + browser.executeScript('arguments[0].scrollIntoView()', this.multipleFileUploadToggle); this.formControllersPage.enableToggle(this.multipleFileUploadToggle); return this; } @@ -75,11 +76,13 @@ export class UploadToggles { } enableExtensionFilter() { + browser.executeScript('arguments[0].scrollIntoView()', this.extensionFilterToggle); this.formControllersPage.enableToggle(this.extensionFilterToggle); return this; } disableExtensionFilter() { + browser.executeScript('arguments[0].scrollIntoView()', this.extensionFilterToggle); this.formControllersPage.disableToggle(this.extensionFilterToggle); return this; } diff --git a/e2e/pages/adf/versionManagerPage.ts b/e2e/pages/adf/versionManagerPage.ts index cc94d79f15..d71b03bace 100644 --- a/e2e/pages/adf/versionManagerPage.ts +++ b/e2e/pages/adf/versionManagerPage.ts @@ -153,9 +153,16 @@ export class VersionManagePage { return this; } - closeActionButton() { + closeActionsMenu() { const container = element(by.css('div.cdk-overlay-backdrop.cdk-overlay-transparent-backdrop.cdk-overlay-backdrop-showing')); - BrowserActions.click(container); + BrowserActions.closeMenuAndDialogs(); + BrowserVisibility.waitUntilElementIsNotVisible(container); + return this; + } + + closeDisabledActionsMenu() { + const container = element(by.css('div.cdk-overlay-backdrop.cdk-overlay-transparent-backdrop.cdk-overlay-backdrop-showing')); + BrowserActions.closeDisabledMenu(); BrowserVisibility.waitUntilElementIsNotVisible(container); return this; } diff --git a/e2e/pages/adf/viewerPage.ts b/e2e/pages/adf/viewerPage.ts index 56138bcc5a..0604d3bea2 100644 --- a/e2e/pages/adf/viewerPage.ts +++ b/e2e/pages/adf/viewerPage.ts @@ -508,6 +508,7 @@ export class ViewerPage { } enableShowTabWithIcon() { + browser.executeScript('arguments[0].scrollIntoView()', this.showTabWithIconSwitch); this.formControllersPage.enableToggle(this.showTabWithIconSwitch); } @@ -552,6 +553,7 @@ export class ViewerPage { } disableAllowLeftSidebar() { + browser.executeScript('arguments[0].scrollIntoView()', this.allowLeftSidebarSwitch); this.formControllersPage.disableToggle(this.allowLeftSidebarSwitch); } @@ -582,11 +584,13 @@ export class ViewerPage { } disableCustomToolbar() { + browser.executeScript('arguments[0].scrollIntoView()', this.customToolbarToggle); this.formControllersPage.disableToggle(this.customToolbarToggle); return this; } enableCustomToolbar() { + browser.executeScript('arguments[0].scrollIntoView()', this.customToolbarToggle); this.formControllersPage.enableToggle(this.customToolbarToggle); return this; } diff --git a/e2e/process-services-cloud/process-filter-results.e2e.ts b/e2e/process-services-cloud/process-filter-results.e2e.ts index 139f804cc0..b42cf96cec 100644 --- a/e2e/process-services-cloud/process-filter-results.e2e.ts +++ b/e2e/process-services-cloud/process-filter-results.e2e.ts @@ -142,47 +142,51 @@ describe('Process filters cloud', () => { }); it('[C306887] Should be able to filter by appName', async () => { - processCloudDemoPage.editProcessFilterCloudComponent().clickCustomiseFilterHeader().setAppNameDropDown(candidateBaseApp).setProperty('initiator', testUser.email); + processCloudDemoPage.editProcessFilterCloudComponent().clickCustomiseFilterHeader().setAppNameDropDown(candidateBaseApp).setProperty('initiator', testUser.username); + processCloudDemoPage.processListCloudComponent().getDataTable().waitTillContentLoaded(); processCloudDemoPage.processListCloudComponent().checkContentIsDisplayedByName(runningProcessInstance.entry.name); processCloudDemoPage.processListCloudComponent().checkContentIsNotDisplayedByName(differentAppUserProcessInstance.entry.name); - }); it('[C306889] Should be able to see "No process found" when using an app with no processes in the appName field', async () => { - processCloudDemoPage.editProcessFilterCloudComponent().clickCustomiseFilterHeader().setAppNameDropDown('subprocessapp').setProperty('initiator', testUser.email); + processCloudDemoPage.editProcessFilterCloudComponent().clickCustomiseFilterHeader().setAppNameDropDown('subprocessapp').setProperty('initiator', testUser.username); + processCloudDemoPage.processListCloudComponent().getDataTable().waitTillContentLoaded(); expect(processListPage.checkProcessListTitleIsDisplayed()).toEqual('No Processes Found'); - }); it('[C306890] Should be able to filter by initiator', async () => { - processCloudDemoPage.editProcessFilterCloudComponent().clickCustomiseFilterHeader().setProperty('initiator', testUser.email); + processCloudDemoPage.editProcessFilterCloudComponent().clickCustomiseFilterHeader().setProperty('initiator', testUser.username); + processCloudDemoPage.processListCloudComponent().getDataTable().waitTillContentLoaded(); processCloudDemoPage.processListCloudComponent().checkContentIsDisplayedByName(runningProcessInstance.entry.name); processCloudDemoPage.processListCloudComponent().checkContentIsNotDisplayedByName(differentAppUserProcessInstance.entry.name); - }); it('[C306891] Should be able to see "No process found" when providing an initiator whitout processes', async () => { - processCloudDemoPage.editProcessFilterCloudComponent().clickCustomiseFilterHeader().setProperty('initiator', anotherUser.email); + processCloudDemoPage.editProcessFilterCloudComponent().clickCustomiseFilterHeader().setProperty('initiator', anotherUser.username); + processCloudDemoPage.processListCloudComponent().getDataTable().waitTillContentLoaded(); expect(processListPage.checkProcessListTitleIsDisplayed()).toEqual('No Processes Found'); - }); it('[C311315] Should be able to filter by process definition id', async () => { processCloudDemoPage.editProcessFilterCloudComponent().clickCustomiseFilterHeader().setProperty('processDefinitionId', processDefinition.entry.id); + processCloudDemoPage.processListCloudComponent().getDataTable().waitTillContentLoaded(); processCloudDemoPage.processListCloudComponent().checkContentIsDisplayedByName(runningProcessInstance.entry.name); + processCloudDemoPage.editProcessFilterCloudComponent().setProperty('processDefinitionId', anotherProcessDefinition.entry.id); + processCloudDemoPage.processListCloudComponent().getDataTable().waitTillContentLoaded(); processCloudDemoPage.processListCloudComponent().checkContentIsDisplayedByName(anotherProcessInstance.entry.name); processCloudDemoPage.processListCloudComponent().checkContentIsNotDisplayedByName(runningProcessInstance.entry.name); - }); it('[C311316] Should be able to filter by process definition key', async () => { processCloudDemoPage.editProcessFilterCloudComponent().clickCustomiseFilterHeader().setProperty('processDefinitionKey', processDefinition.entry.key); + processCloudDemoPage.processListCloudComponent().getDataTable().waitTillContentLoaded(); processCloudDemoPage.processListCloudComponent().checkContentIsDisplayedByName(runningProcessInstance.entry.name); + processCloudDemoPage.editProcessFilterCloudComponent().setProperty('processDefinitionKey', anotherProcessDefinition.entry.key); + processCloudDemoPage.processListCloudComponent().getDataTable().waitTillContentLoaded(); processCloudDemoPage.processListCloudComponent().checkContentIsDisplayedByName(anotherProcessInstance.entry.name); processCloudDemoPage.processListCloudComponent().checkContentIsNotDisplayedByName(runningProcessInstance.entry.name); - }); it('[C311317] Should be able to filter by process instance id', async () => { @@ -196,36 +200,31 @@ describe('Process filters cloud', () => { processCloudDemoPage.processListCloudComponent().checkContentIsDisplayedByName(anotherProcessInstance.entry.name); processCloudDemoPage.processListCloudComponent().checkContentIsNotDisplayedByName(runningProcessInstance.entry.name); expect(processCloudDemoPage.processListCloudComponent().getDataTable().getNumberOfRows()).toBe(1); - }); it('[C311321] Should be able to filter by process name', async () => { processCloudDemoPage.editProcessFilterCloudComponent().clickCustomiseFilterHeader().setProperty('processName', runningProcessInstance.entry.name); + processCloudDemoPage.processListCloudComponent().getDataTable().waitTillContentLoaded(); processCloudDemoPage.processListCloudComponent().checkContentIsDisplayedByName(runningProcessInstance.entry.name); + processCloudDemoPage.editProcessFilterCloudComponent().setProperty('processName', anotherProcessInstance.entry.name); + processCloudDemoPage.processListCloudComponent().getDataTable().waitTillContentLoaded(); processCloudDemoPage.processListCloudComponent().checkContentIsDisplayedByName(anotherProcessInstance.entry.name); processCloudDemoPage.processListCloudComponent().checkContentIsNotDisplayedByName(runningProcessInstance.entry.name); - }); it('[C306892] Should be able to filter by process status - Running', async () => { processCloudDemoPage.editProcessFilterCloudComponent().clickCustomiseFilterHeader().setStatusFilterDropDown('RUNNING'); + processCloudDemoPage.processListCloudComponent().getDataTable().waitTillContentLoaded(); processCloudDemoPage.processListCloudComponent().checkContentIsDisplayedByName(runningProcessInstance.entry.name); processCloudDemoPage.processListCloudComponent().checkContentIsNotDisplayedByName(suspendProcessInstance.entry.name); - processCloudDemoPage.processListCloudComponent().checkContentIsNotDisplayedByName(anotherProcessInstance.entry.name); - processCloudDemoPage.processListCloudComponent().checkContentIsNotDisplayedByName(completedProcess.entry.name); - }); - - it('[C306892] Should be able to filter by process status - Created', async () => { - processCloudDemoPage.editProcessFilterCloudComponent().clickCustomiseFilterHeader().setStatusFilterDropDown('CREATED'); processCloudDemoPage.processListCloudComponent().checkContentIsDisplayedByName(anotherProcessInstance.entry.name); - processCloudDemoPage.processListCloudComponent().checkContentIsNotDisplayedByName(runningProcessInstance.entry.name); - processCloudDemoPage.processListCloudComponent().checkContentIsNotDisplayedByName(suspendProcessInstance.entry.name); processCloudDemoPage.processListCloudComponent().checkContentIsNotDisplayedByName(completedProcess.entry.name); }); it('[C306892] Should be able to filter by process status - Completed', async () => { processCloudDemoPage.editProcessFilterCloudComponent().clickCustomiseFilterHeader().setStatusFilterDropDown('COMPLETED'); + processCloudDemoPage.processListCloudComponent().getDataTable().waitTillContentLoaded(); processCloudDemoPage.processListCloudComponent().checkContentIsDisplayedByName(completedProcess.entry.name); processCloudDemoPage.processListCloudComponent().checkContentIsNotDisplayedByName(runningProcessInstance.entry.name); processCloudDemoPage.processListCloudComponent().checkContentIsNotDisplayedByName(suspendProcessInstance.entry.name); @@ -234,6 +233,7 @@ describe('Process filters cloud', () => { it('[C306892] Should be able to filter by process status - Suspended', async () => { processCloudDemoPage.editProcessFilterCloudComponent().clickCustomiseFilterHeader().setStatusFilterDropDown('SUSPENDED'); + processCloudDemoPage.processListCloudComponent().getDataTable().waitTillContentLoaded(); processCloudDemoPage.processListCloudComponent().checkContentIsDisplayedByName(suspendProcessInstance.entry.name); processCloudDemoPage.processListCloudComponent().checkContentIsNotDisplayedByName(runningProcessInstance.entry.name); processCloudDemoPage.processListCloudComponent().checkContentIsNotDisplayedByName(anotherProcessInstance.entry.name); @@ -242,6 +242,7 @@ describe('Process filters cloud', () => { it('[C306892] Should be able to filter by process status - All', async () => { processCloudDemoPage.editProcessFilterCloudComponent().clickCustomiseFilterHeader().setStatusFilterDropDown('ALL'); + processCloudDemoPage.processListCloudComponent().getDataTable().waitTillContentLoaded(); processCloudDemoPage.processListCloudComponent().checkContentIsDisplayedByName(runningProcessInstance.entry.name); processCloudDemoPage.processListCloudComponent().checkContentIsDisplayedByName(anotherProcessInstance.entry.name); processCloudDemoPage.processListCloudComponent().checkContentIsDisplayedByName(suspendProcessInstance.entry.name); @@ -250,48 +251,44 @@ describe('Process filters cloud', () => { it('[C311318] Should be able to filter by lastModifiedFrom - displays record when date = currentDate', async () => { processCloudDemoPage.editProcessFilterCloudComponent().clickCustomiseFilterHeader().setProperty('lastModifiedFrom', currentDate); + processCloudDemoPage.processListCloudComponent().getDataTable().waitTillContentLoaded(); processCloudDemoPage.processListCloudComponent().checkContentIsDisplayedByName(runningProcessInstance.entry.name); - }); it('[C311318] Should be able to filter by lastModifiedFrom - displays record when date = beforeDate', async () => { - processCloudDemoPage.editProcessFilterCloudComponent().clickCustomiseFilterHeader().setProperty('lastModifiedFrom', beforeDate); + processCloudDemoPage.processListCloudComponent().getDataTable().waitTillContentLoaded(); processCloudDemoPage.processListCloudComponent().checkContentIsDisplayedByName(runningProcessInstance.entry.name); - }); it('[C311318] Should be able to filter by lastModifiedFrom - does not display record when date = afterDate', async () => { - processCloudDemoPage.editProcessFilterCloudComponent().clickCustomiseFilterHeader().setProperty('lastModifiedFrom', afterDate); + processCloudDemoPage.processListCloudComponent().getDataTable().waitTillContentLoaded(); processCloudDemoPage.processListCloudComponent().checkContentIsNotDisplayedByName(runningProcessInstance.entry.name); - }); it('[C311319] Should be able to filter by lastModifiedTo - displays record when date = currentDate', async () => { processCloudDemoPage.editProcessFilterCloudComponent().clickCustomiseFilterHeader().setProperty('lastModifiedTo', currentDate); + processCloudDemoPage.processListCloudComponent().getDataTable().waitTillContentLoaded(); processCloudDemoPage.processListCloudComponent().checkContentIsDisplayedByName(runningProcessInstance.entry.name); - }); it('[C311319] Should be able to filter by lastModifiedTo - does not display record when date = beforeDate', async () => { - processCloudDemoPage.editProcessFilterCloudComponent().clickCustomiseFilterHeader().setProperty('lastModifiedTo', beforeDate); + processCloudDemoPage.processListCloudComponent().getDataTable().waitTillContentLoaded(); processCloudDemoPage.processListCloudComponent().checkContentIsNotDisplayedByName(runningProcessInstance.entry.name); - }); it('[C311319] Should be able to filter by lastModifiedTo - displays record when date = afterDate', async () => { - processCloudDemoPage.editProcessFilterCloudComponent().clickCustomiseFilterHeader().setProperty('lastModifiedTo', afterDate); + processCloudDemoPage.processListCloudComponent().getDataTable().waitTillContentLoaded(); processCloudDemoPage.processListCloudComponent().checkContentIsDisplayedByName(runningProcessInstance.entry.name); - }); it('[C311319] Should not display any processes when the lastModifiedFrom and lastModifiedTo are set to a future date', () => { - processCloudDemoPage.editProcessFilterCloudComponent().clickCustomiseFilterHeader().setProperty('lastModifiedFrom', afterDate); processCloudDemoPage.editProcessFilterCloudComponent().setProperty('lastModifiedTo', afterDate); + processCloudDemoPage.processListCloudComponent().getDataTable().waitTillContentLoaded(); expect(processListPage.checkProcessListTitleIsDisplayed()).toEqual('No Processes Found'); }); diff --git a/lib/process-services-cloud/src/lib/process/start-process/components/start-process-cloud.component.spec.ts b/lib/process-services-cloud/src/lib/process/start-process/components/start-process-cloud.component.spec.ts index 1e7782078d..26751d3a6c 100755 --- a/lib/process-services-cloud/src/lib/process/start-process/components/start-process-cloud.component.spec.ts +++ b/lib/process-services-cloud/src/lib/process/start-process/components/start-process-cloud.component.spec.ts @@ -387,7 +387,7 @@ describe('StartProcessCloudComponent', () => { expect(component.processDefinitionList).toBe(fakeProcessDefinitions); }); - it('should filter processes in the select list if input is empty', fakeAsync(() => { + xit('should NOT filter processes in the select list if input is empty', fakeAsync(() => { component.processDefinitionList = fakeProcessDefinitions; component.ngOnInit(); component.ngOnChanges({ appName: change }); @@ -398,9 +398,10 @@ describe('StartProcessCloudComponent', () => { el.dispatchEvent(new Event('keyup')); el.dispatchEvent(new Event('input')); fixture.detectChanges(); + expect(component.processDefinition.value).toEqual('', 'processDefinition value should be the one from input'); tick(3000); - expect(component.filteredProcesses.length).toEqual(1); + expect(component.filteredProcesses.length).toEqual(fakeProcessDefinitions.length); })); it('should display the matching results in the dropdown as the user types down', fakeAsync(() => { diff --git a/lib/testing/src/lib/core/pages/header.page.ts b/lib/testing/src/lib/core/pages/header.page.ts index fbaa677b6e..087464ca00 100644 --- a/lib/testing/src/lib/core/pages/header.page.ts +++ b/lib/testing/src/lib/core/pages/header.page.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import { element, by, protractor } from 'protractor'; +import { element, by, protractor, browser } from 'protractor'; import { BrowserVisibility } from '../utils/browser-visibility'; import { BrowserActions } from '../utils/browser-actions'; @@ -114,12 +114,11 @@ export class HeaderPage { sideBarPositionStart() { return BrowserActions.click(this.positionStart); - } sideBarPositionEnd() { + browser.executeScript('arguments[0].scrollIntoView()', this.positionEnd); return BrowserActions.click(this.positionEnd); - } checkSidebarPositionStart() { diff --git a/lib/testing/src/lib/core/utils/browser-actions.ts b/lib/testing/src/lib/core/utils/browser-actions.ts index 9372253218..049d04c211 100644 --- a/lib/testing/src/lib/core/utils/browser-actions.ts +++ b/lib/testing/src/lib/core/utils/browser-actions.ts @@ -58,6 +58,11 @@ export class BrowserActions { return browser.actions().sendKeys(protractor.Key.ESCAPE).perform(); } + static async closeDisabledMenu() { + // if the opened menu has only disabled items, pressing escape to close it won't work + return browser.actions().sendKeys(protractor.Key.ENTER).perform(); + } + static clickOnDropdownOption(option: string, dropDownElement: ElementFinder) { this.click(dropDownElement); BrowserVisibility.waitUntilElementIsVisible(element('div[class*="mat-menu-content"] button')); diff --git a/lib/testing/src/lib/core/utils/browser-visibility.ts b/lib/testing/src/lib/core/utils/browser-visibility.ts index bd6b51a261..e2acfc030c 100644 --- a/lib/testing/src/lib/core/utils/browser-visibility.ts +++ b/lib/testing/src/lib/core/utils/browser-visibility.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import { browser, by, element, ElementFinder, protractor } from 'protractor'; +import { browser, by, element, ExpectedConditions as EC, ElementFinder, protractor } from 'protractor'; const until = protractor.ExpectedConditions; const DEFAULT_TIMEOUT = global['TestConfig'] ? global['TestConfig'].main.timeout : 40000; @@ -46,25 +46,13 @@ export class BrowserVisibility { * Wait for element to be clickable */ static waitUntilElementIsClickable(elementToCheck: ElementFinder, waitTimeout: number = DEFAULT_TIMEOUT) { - let isDisplayed = false; - return browser.wait(() => { - browser.waitForAngularEnabled(); - - elementToCheck.isDisplayed().then( - () => { - isDisplayed = true; - }, - () => { - isDisplayed = false; - } - ); - return isDisplayed; - }, waitTimeout, 'Element is not Clickable ' + elementToCheck.locator()); + return browser.wait(EC.elementToBeClickable(elementToCheck), + waitTimeout, 'Element is not Clickable ' + elementToCheck.locator()); } /* - * Wait for element to not be visible - */ + * Wait for element to not be present on the page + */ static waitUntilElementIsStale(elementToCheck: ElementFinder, waitTimeout: number = DEFAULT_TIMEOUT) { return browser.wait(until.stalenessOf(elementToCheck), waitTimeout, 'Element is not in stale ' + elementToCheck.locator()); } @@ -103,7 +91,7 @@ export class BrowserVisibility { * Wait for element to not be visible */ static waitUntilElementIsNotOnPage(elementToCheck: ElementFinder, waitTimeout: number = DEFAULT_TIMEOUT) { - return browser.wait(until.not(until.visibilityOf(elementToCheck)), waitTimeout, 'Element is not in the page ' + elementToCheck.locator()); + return browser.wait(until.invisibilityOf(elementToCheck), waitTimeout, 'Element is visible on the page ' + elementToCheck.locator()); } static waitUntilElementIsPresent(elementToCheck: ElementFinder, waitTimeout: number = DEFAULT_TIMEOUT) { @@ -113,7 +101,7 @@ export class BrowserVisibility { } static waitUntilElementIsNotPresent(elementToCheck: ElementFinder, waitTimeout: number = DEFAULT_TIMEOUT) { - return browser.wait(until.not(until.presenceOf(elementToCheck)), waitTimeout, 'Element is not in the page ' + elementToCheck.locator()); + return browser.wait(until.stalenessOf(elementToCheck), waitTimeout, 'Element is present ' + elementToCheck.locator()); } static waitUntilDialogIsClose() { diff --git a/lib/testing/src/lib/process-services-cloud/pages/start-process-cloud-component.page.ts b/lib/testing/src/lib/process-services-cloud/pages/start-process-cloud-component.page.ts index e88ef1a72e..25ddb073d1 100644 --- a/lib/testing/src/lib/process-services-cloud/pages/start-process-cloud-component.page.ts +++ b/lib/testing/src/lib/process-services-cloud/pages/start-process-cloud-component.page.ts @@ -83,7 +83,6 @@ export class StartProcessCloudPage { } checkStartProcessButtonIsEnabled() { - BrowserVisibility.waitUntilElementIsClickable(this.startProcessButton); return this.startProcessButton.isEnabled(); } diff --git a/package-lock.json b/package-lock.json index 3a99fd1c3e..6b832785af 100644 --- a/package-lock.json +++ b/package-lock.json @@ -70,12 +70,12 @@ } }, "@angular-devkit/architect": { - "version": "0.13.6", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.13.6.tgz", - "integrity": "sha512-Cg9z4lmCvjt5uD00E/0tBRz3ESjYicmqT3NL/BIsNVNb+s1GwCCoPSOIM8Ss4nyGDtrdono1XKSOmkJnlzF3Cw==", + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.13.9.tgz", + "integrity": "sha512-EAFtCs9dsGhpMRC45PoYsrkiExpWz9Ax15qXfzwdDRacz5DmdOVt+QpkLW1beUOwiyj/bhFyj23eaONK2RTn/w==", "dev": true, "requires": { - "@angular-devkit/core": "7.3.6", + "@angular-devkit/core": "7.3.9", "rxjs": "6.3.3" }, "dependencies": { @@ -446,9 +446,9 @@ } }, "@angular-devkit/core": { - "version": "7.3.6", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-7.3.6.tgz", - "integrity": "sha512-aoarMK0DJIdwjVA0OuQIN7b8nKPcF9n5vSMF7MFmhKpTw5/uV3SynQZbm3YCgylu/2CMuiTzKuAunnWWdli//g==", + "version": "7.3.9", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-7.3.9.tgz", + "integrity": "sha512-SaxD+nKFW3iCBKsxNR7+66J30EexW/y7tm8m5AvUH+GwSAgIj0ZYmRUzFEPggcaLVA4WnE/YWqIXZMJW5dT7gw==", "dev": true, "requires": { "ajv": "6.9.1", @@ -488,12 +488,12 @@ } }, "@angular-devkit/schematics": { - "version": "7.3.6", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-7.3.6.tgz", - "integrity": "sha512-YXF7QusmMy3D9H0vNczc1n5BkuEHLwt7cW33euNeGNgTIsD0n6DrUhgClurXicnr2GNPSDYE5+3115lmJkhyrg==", + "version": "7.3.9", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-7.3.9.tgz", + "integrity": "sha512-xzROGCYp7aQbeJ3V6YC0MND7wKEAdWqmm/GaCufEk0dDS8ZGe0sQhcM2oBRa2nQqGQNeThFIH51kx+FayrJP0w==", "dev": true, "requires": { - "@angular-devkit/core": "7.3.6", + "@angular-devkit/core": "7.3.9", "rxjs": "6.3.3" }, "dependencies": { @@ -509,63 +509,63 @@ } }, "@angular/animations": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-7.0.3.tgz", - "integrity": "sha512-jCRHlt+ghfSnP5a8HKr6R/Adc5Cq7i/mcYsn3V6M2QBpGFCVmy0ZWZa66QOhRaqler8u8EGi1PdoCCoGAZc4OA==", + "version": "7.2.15", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-7.2.15.tgz", + "integrity": "sha512-8oBt3HLgd2+kyJHUgsd7OzKCCss67t2sch15XNoIWlOLfxclqU+EfFE6t/vCzpT8/+lpZS6LU9ZrTnb+UBj5jg==", "requires": { "tslib": "^1.9.0" } }, "@angular/cdk": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-7.0.3.tgz", - "integrity": "sha512-QT7U2tOBVfwn8Q71Nyh0UjlyXfZNKdanq3+b8GJ/+IB/d8mVdMRTXBGQ4PqY7CP+wpkgm+wbbUt3urZF1AqdmQ==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-7.3.7.tgz", + "integrity": "sha512-xbXxhHHKGkVuW6K7pzPmvpJXIwpl0ykBnvA2g+/7Sgy5Pd35wCC+UtHD9RYczDM/mkygNxMQtagyCErwFnDtQA==", "requires": { "parse5": "^5.0.0", "tslib": "^1.7.1" } }, "@angular/cli": { - "version": "7.3.6", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-7.3.6.tgz", - "integrity": "sha512-u5lBcYVQRk9cez/DozJvFOYomeko9b5kE+NElyFhPtM3GF1SBcXKb5QyNxH/zSOc850VL7KPe7ZfC6kW3Phhyw==", + "version": "7.3.9", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-7.3.9.tgz", + "integrity": "sha512-7oJj7CKDlFUbQav1x1CV4xKKcbt0pnxY4unKcm7Q1tVXhu8bU2bc3cDA0aJnbofcYb6TJcd/C2qHgCt78q7edA==", "dev": true, "requires": { - "@angular-devkit/architect": "0.13.6", - "@angular-devkit/core": "7.3.6", - "@angular-devkit/schematics": "7.3.6", - "@schematics/angular": "7.3.6", - "@schematics/update": "0.13.6", + "@angular-devkit/architect": "0.13.9", + "@angular-devkit/core": "7.3.9", + "@angular-devkit/schematics": "7.3.9", + "@schematics/angular": "7.3.9", + "@schematics/update": "0.13.9", "@yarnpkg/lockfile": "1.1.0", "ini": "1.3.5", "inquirer": "6.2.1", "npm-package-arg": "6.1.0", - "opn": "5.4.0", + "open": "6.0.0", "pacote": "9.4.0", "semver": "5.6.0", "symbol-observable": "1.2.0" } }, "@angular/common": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-7.0.3.tgz", - "integrity": "sha512-aiuQh6+5kWFp34SYEtpnkAJWU3Qn17S/9LjWSZbgfiaYG6MyszepxqLZPBSBPTElxx2u5VoCPh97+TpKoDqx+g==", + "version": "7.2.15", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-7.2.15.tgz", + "integrity": "sha512-2b5JY2HWVHCf3D1GZjmde7jdAXSTXkYtmjLtA9tQkjOOTr80eHpNSujQqnzb97dk9VT9OjfjqTQd7K3pxZz8jw==", "requires": { "tslib": "^1.9.0" } }, "@angular/compiler": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-7.0.3.tgz", - "integrity": "sha512-1eF4PzWej9eoEQhHwuMxujx9B4oSjP70vORIs9pgXF8O4nWDWTKtfPQyNCPxc8mY+Fwb0+nSOEvvA+Ou8Hnreg==", + "version": "7.2.15", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-7.2.15.tgz", + "integrity": "sha512-5yb4NcLk8GuXkYf7Dcor4XkGueYp4dgihzDmMjYDUrV0NPhubKlr+SwGtLOtzgRBWJ1I2bO0S3zwa0q0OgIPOw==", "requires": { "tslib": "^1.9.0" } }, "@angular/compiler-cli": { - "version": "7.2.9", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-7.2.9.tgz", - "integrity": "sha512-3itdcfszdyXTHYEsO4eBu4WEx10hU8JpOgUcZyw+OYgwLQLyjEXOD9dfYZZpE/+2F0omoMLseCTHTP//uux+Iw==", + "version": "7.2.15", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-7.2.15.tgz", + "integrity": "sha512-+AsfyKawmj/sa+m4Pz8VSRFbCfx/3IOjAuuEjhopbyr154YpPDSu8NTbcwzq3yfbVcPwK4/4exmbQzpsndaCTg==", "dev": true, "requires": { "canonical-path": "1.0.0", @@ -594,9 +594,9 @@ "dev": true }, "chokidar": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.2.tgz", - "integrity": "sha512-IwXUx0FXc5ibYmPC2XeEj5mpXoV66sR+t3jqu2NS2GYwCktt3KF1/Qqjws/NkegajBA4RbZ5+DDwlOiJsxDHEg==", + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.6.tgz", + "integrity": "sha512-V2jUo67OKkc6ySiRpJrjlpJKl9kDuG+Xb8VgsGzb+aEouhgS1D0weyPU4lEzdAcsCAvrih2J2BqyXqHWvVLw5g==", "dev": true, "requires": { "anymatch": "^2.0.0", @@ -610,7 +610,7 @@ "normalize-path": "^3.0.0", "path-is-absolute": "^1.0.0", "readdirp": "^2.2.1", - "upath": "^1.1.0" + "upath": "^1.1.1" } }, "cross-spawn": { @@ -801,73 +801,73 @@ } }, "@angular/core": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-7.0.3.tgz", - "integrity": "sha512-x/OYYykVsi2vrKlYQJ37I8HYAI/s/CtL3Sd9bl87F6AnqLWnnKIxQaofT/ShfAfdP44LQoN5BNp5j+sjs8K4Kg==", + "version": "7.2.15", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-7.2.15.tgz", + "integrity": "sha512-XsuYm0jEU/mOqwDOk2utThv8J9kESkAerfuCHClE9rB2TtHUOGCfekF7lJWqjjypu6/J9ygoPFo7hdAE058ZGg==", "requires": { "tslib": "^1.9.0" } }, "@angular/flex-layout": { - "version": "7.0.0-beta.23", - "resolved": "https://registry.npmjs.org/@angular/flex-layout/-/flex-layout-7.0.0-beta.23.tgz", - "integrity": "sha512-jH2i3i/M7SbK6scVlj2urVL5OhzwavbQ7KwvUjyc/UwccKnnzuOuWEGCINLja/aoaUO3I35LluCLv6a6VN0olA==", + "version": "7.0.0-beta.24", + "resolved": "https://registry.npmjs.org/@angular/flex-layout/-/flex-layout-7.0.0-beta.24.tgz", + "integrity": "sha512-ll6sK0nLGxqI/f5+z4jbd+pve1QITzgehv2AuGvfSDgIjPMeqUDB5YZqQmIGM/dQRk/vIio5KCW5LQPJWzMMYQ==", "requires": { "tslib": "^1.7.1" } }, "@angular/forms": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-7.0.3.tgz", - "integrity": "sha512-URbSpsNDQOg2NxmAt2FgeXIbEXvJS2yQwP02NLkHGqqCe38dpcifijj6HlUxeH14ZBkoqeTQjtSkXlMkgt22YA==", + "version": "7.2.15", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-7.2.15.tgz", + "integrity": "sha512-p0kcIQLtBBC1qeTA6M3nOuXf/k91E80FKquVM9zEsO2kDjI0oZJVfFYL2UMov5samlJOPN+t6lRHEIUa7ApPsw==", "requires": { "tslib": "^1.9.0" } }, "@angular/http": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/@angular/http/-/http-7.0.3.tgz", - "integrity": "sha512-aL+z1/tbVY8oJw5v46rbMli5vBGDVyJvs95d1l2n3hWnwMTzS9AVetjcL3B3uruAYuXoh4QlSJ+ysBgdmV1+IA==", + "version": "7.2.15", + "resolved": "https://registry.npmjs.org/@angular/http/-/http-7.2.15.tgz", + "integrity": "sha512-TR7PEdmLWNIre3Zn8lvyb4lSrvPUJhKLystLnp4hBMcWsJqq5iK8S3bnlR4viZ9HMlf7bW7+Hm4SI6aB3tdUtw==", "requires": { "tslib": "^1.9.0" } }, "@angular/material": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/@angular/material/-/material-7.0.3.tgz", - "integrity": "sha512-acJ2zU44k/rsd4OeTdAMVP0R3te8aXwfubDQGc8YI1CdRVW1XqMSvAWkToYDVaGvnZV53zQt/iSi1XWaSXYf1Q==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/@angular/material/-/material-7.3.7.tgz", + "integrity": "sha512-Eq+7frkeNGkLOfEtmkmJgR+AgoWajOipXZWWfCSamNfpCcPof82DwvGOpAmgGni9FuN2XFQdqP5MoaffQzIvUA==", "requires": { "tslib": "^1.7.1" } }, "@angular/material-moment-adapter": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/@angular/material-moment-adapter/-/material-moment-adapter-7.0.3.tgz", - "integrity": "sha512-vbynHlQYWcgbZKRearq5LpflQp9VPDDNarHL+C4WD6aGLPYmIKotOWcBr083HfN1RnkCa7fh+GhOld/MHglHmg==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/@angular/material-moment-adapter/-/material-moment-adapter-7.3.7.tgz", + "integrity": "sha512-Nb8hZkF6zcni7Jb+FXcTKKmbp8PhhFAhJSkch9FnKcFs1Py+sCNTLIH/cI53nPrTglkJwlVLwMW7fxj4w9I1CQ==", "requires": { "tslib": "^1.7.1" } }, "@angular/platform-browser": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-7.0.3.tgz", - "integrity": "sha512-OKDGce2dYw9Fw8agpcSNJA+ecMMnMQCi9xoPHNIp1pYdvte7mUXKUvUzR7chqQ7b83d7SzVeEhqAZYa4BUwFRA==", + "version": "7.2.15", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-7.2.15.tgz", + "integrity": "sha512-aYgmPsbC9Tvp9vmKWD8voeAp4crwCay7/D6lM3ClEe2EeK934LuEXq3/uczMrFVbnIX7BBIo8fh03Tl7wbiGPw==", "requires": { "tslib": "^1.9.0" } }, "@angular/platform-browser-dynamic": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-7.0.3.tgz", - "integrity": "sha512-hrdBtlkKyq2CZRY6z2RWFTcGF4n4MirM7EEzByEjlgiXSU+c4qHYb0a8z30qdCF1D/DZ6Md7cRRH+1uR/rCqxQ==", + "version": "7.2.15", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-7.2.15.tgz", + "integrity": "sha512-UL2PqhzXMD769NQ6Lh6pxlBDKvN9Qol3XLRFil80lwJ1GRW16ITeYbCamcafIH2GOyd88IhmYcbMfUQ/6q4MMQ==", "requires": { "tslib": "^1.9.0" } }, "@angular/router": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-7.0.3.tgz", - "integrity": "sha512-885svORDpD9DkaMKjvGwn4g5bf0n3JR8os+gCNhzk0p4TPfpc+vmNo8SyY2jwdLMh2rQzrUQTDkn9SzzgiOfDQ==", + "version": "7.2.15", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-7.2.15.tgz", + "integrity": "sha512-qAubRJRQanguUqJQ76J9GSZ4JFtoyhJKRmX5P23ANZJXpB6YLzF2fJmOGi+E6cV8F0tKBMEq1pjxFTisx0MXwQ==", "requires": { "tslib": "^1.9.0" } @@ -1457,13 +1457,13 @@ } }, "@schematics/angular": { - "version": "7.3.6", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-7.3.6.tgz", - "integrity": "sha512-Q4VXAjVaCDb2zXFXoIdOfNPsn+EQjqDBHK4a97omytnSNAmu1erl3l2FkEMi6x/VuzK2mQSzBbmHJIgauMmOAA==", + "version": "7.3.9", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-7.3.9.tgz", + "integrity": "sha512-B3lytFtFeYNLfWdlrIzvy3ulFRccD2/zkoL0734J+DAGfUz7vbysJ50RwYL46sQUcKdZdvb48ktfu1S8yooP6Q==", "dev": true, "requires": { - "@angular-devkit/core": "7.3.6", - "@angular-devkit/schematics": "7.3.6", + "@angular-devkit/core": "7.3.9", + "@angular-devkit/schematics": "7.3.9", "typescript": "3.2.4" }, "dependencies": { @@ -1476,13 +1476,13 @@ } }, "@schematics/update": { - "version": "0.13.6", - "resolved": "https://registry.npmjs.org/@schematics/update/-/update-0.13.6.tgz", - "integrity": "sha512-TkeigdQTHG40ZGj4CAAzQHh7/rSotg0J6nkBBtc4Y+9md7IGg6dzSFJAvYbDX5JZ9tk7DpukdRHOVVopS/J0AQ==", + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/@schematics/update/-/update-0.13.9.tgz", + "integrity": "sha512-4MQcaKFxhMzZyE//+DknDh3h3duy3avg2oxSHxdwXlCZ8Q92+4lpegjJcSRiqlEwO4qeJ5XnrjrvzfIiaIZOmA==", "dev": true, "requires": { - "@angular-devkit/core": "7.3.6", - "@angular-devkit/schematics": "7.3.6", + "@angular-devkit/core": "7.3.9", + "@angular-devkit/schematics": "7.3.9", "@yarnpkg/lockfile": "1.1.0", "ini": "1.3.5", "pacote": "9.4.0", @@ -3044,12 +3044,12 @@ } }, "browser-sync": { - "version": "2.26.5", - "resolved": "https://registry.npmjs.org/browser-sync/-/browser-sync-2.26.5.tgz", - "integrity": "sha512-zVa6MmadAFgl5Uk53Yy5cw5tGTO7xSGAWK3Yx70GJ1t5jK+r6B4q3xq+1XbYfLt1SbeFg7WoNWneNhMT4B9jFw==", + "version": "2.26.7", + "resolved": "https://registry.npmjs.org/browser-sync/-/browser-sync-2.26.7.tgz", + "integrity": "sha512-lY3emme0OyvA2ujEMpRmyRy9LY6gHLuTr2/ABxhIm3lADOiRXzP4dgekvnDrQqZ/Ec2Fz19lEjm6kglSG5766w==", "dev": true, "requires": { - "browser-sync-client": "^2.26.4", + "browser-sync-client": "^2.26.6", "browser-sync-ui": "^2.26.4", "bs-recipes": "1.3.4", "bs-snippet-injector": "^2.0.1", @@ -3064,7 +3064,7 @@ "fs-extra": "3.0.1", "http-proxy": "1.15.2", "immutable": "^3", - "localtunnel": "1.9.1", + "localtunnel": "1.9.2", "micromatch": "^3.1.10", "opn": "5.3.0", "portscanner": "2.1.1", @@ -3178,9 +3178,9 @@ } }, "browser-sync-client": { - "version": "2.26.4", - "resolved": "https://registry.npmjs.org/browser-sync-client/-/browser-sync-client-2.26.4.tgz", - "integrity": "sha512-mQiDp5/tf79VezDS5j/EExU4Ze6f5DQYuL0Z7VdJgBbNLTHDfkYGi2R620qc6HkY9XZA0m4/UwihT7J42RBIJA==", + "version": "2.26.6", + "resolved": "https://registry.npmjs.org/browser-sync-client/-/browser-sync-client-2.26.6.tgz", + "integrity": "sha512-mGrkZdNzttKdf/16I+y+2dTQxoMCIpKbVIMJ/uP8ZpnKu9f9qa/2CYVtLtbjZG8nsM14EwiCrjuFTGBEnT3Gjw==", "dev": true, "requires": { "etag": "1.8.1", @@ -6483,9 +6483,9 @@ } }, "fs-minipass": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz", - "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.6.tgz", + "integrity": "sha512-crhvyXcMejjv3Z5d2Fa9sf5xLYVCF5O1c71QxbVnbLsmYMBEvDAftewesN/HhY03YRoA7zOMxjNGrF5svGaaeQ==", "dev": true, "requires": { "minipass": "^2.2.1" @@ -7163,41 +7163,48 @@ } }, "github-build": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/github-build/-/github-build-1.2.0.tgz", - "integrity": "sha512-Iq7NialLYz5yRZDkiX8zaOWd+N3BssJJfUvG7wd8r4MeLCN88SdxEYo2esseMLpLtP4vNXhgamg1eRm7hw59qw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/github-build/-/github-build-1.2.1.tgz", + "integrity": "sha512-VAT4NFU8hm9Ks5yNKuuczD2zMbmouAKHtxtwvmCj34Q2DpZsjgp3LLjtrKlm/YvGSzSNGmj22ccJQQei+f/vIw==", "dev": true, "requires": { - "axios": "0.15.3" + "axios": "0.19.0" }, "dependencies": { "axios": { - "version": "0.15.3", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.15.3.tgz", - "integrity": "sha1-LJ1jiy4ZGgjqHWzJiOrda6W9wFM=", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.0.tgz", + "integrity": "sha512-1uvKqKQta3KBxIz14F2v06AEHZ/dIoeKfbTRkK1E5oqjDnuEerLmYTgJB5AiQZHJcljpg1TuRzdjDR06qNk0DQ==", "dev": true, "requires": { - "follow-redirects": "1.0.0" + "follow-redirects": "1.5.10", + "is-buffer": "^2.0.2" } }, "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "dev": true, "requires": { "ms": "2.0.0" } }, "follow-redirects": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.0.0.tgz", - "integrity": "sha1-jjQpjL0uF28lTv/sdaHHjMhJ/Tc=", + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", + "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", "dev": true, "requires": { - "debug": "^2.2.0" + "debug": "=3.1.0" } }, + "is-buffer": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.3.tgz", + "integrity": "sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw==", + "dev": true + }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -9988,25 +9995,25 @@ } }, "localtunnel": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/localtunnel/-/localtunnel-1.9.1.tgz", - "integrity": "sha512-HWrhOslklDvxgOGFLxi6fQVnvpl6XdX4sPscfqMZkzi3gtt9V7LKBWYvNUcpHSVvjwCQ6xzXacVvICNbNcyPnQ==", + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/localtunnel/-/localtunnel-1.9.2.tgz", + "integrity": "sha512-NEKF7bDJE9U3xzJu3kbayF0WTvng6Pww7tzqNb/XtEARYwqw7CKEX7BvOMg98FtE9es2CRizl61gkV3hS8dqYg==", "dev": true, "requires": { - "axios": "0.17.1", - "debug": "2.6.9", + "axios": "0.19.0", + "debug": "4.1.1", "openurl": "1.1.1", "yargs": "6.6.0" }, "dependencies": { "axios": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.17.1.tgz", - "integrity": "sha1-LY4+XQvb1zJ/kbyBT1xXZg+Bgk0=", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.0.tgz", + "integrity": "sha512-1uvKqKQta3KBxIz14F2v06AEHZ/dIoeKfbTRkK1E5oqjDnuEerLmYTgJB5AiQZHJcljpg1TuRzdjDR06qNk0DQ==", "dev": true, "requires": { - "follow-redirects": "^1.2.5", - "is-buffer": "^1.1.5" + "follow-redirects": "1.5.10", + "is-buffer": "^2.0.2" } }, "camelcase": { @@ -10016,14 +10023,48 @@ "dev": true }, "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "dev": true, "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" + }, + "dependencies": { + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } } }, + "follow-redirects": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", + "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", + "dev": true, + "requires": { + "debug": "=3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "is-buffer": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.3.tgz", + "integrity": "sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw==", + "dev": true + }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -10434,23 +10475,29 @@ "ssri": "^6.0.0" }, "dependencies": { + "bluebird": { + "version": "3.5.5", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.5.tgz", + "integrity": "sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w==", + "dev": true + }, "cacache": { - "version": "11.3.2", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-11.3.2.tgz", - "integrity": "sha512-E0zP4EPGDOaT2chM08Als91eYnf8Z+eH1awwwVsngUmgppfM5jjJ8l3z5vO5p5w/I3LsiXawb1sW0VY65pQABg==", + "version": "11.3.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-11.3.3.tgz", + "integrity": "sha512-p8WcneCytvzPxhDvYp31PD039vi77I12W+/KfR9S8AZbaiARFBCpsPJS+9uhWfeBfeAtW7o/4vt3MUqLkbY6nA==", "dev": true, "requires": { - "bluebird": "^3.5.3", + "bluebird": "^3.5.5", "chownr": "^1.1.1", "figgy-pudding": "^3.5.1", - "glob": "^7.1.3", + "glob": "^7.1.4", "graceful-fs": "^4.1.15", "lru-cache": "^5.1.1", "mississippi": "^3.0.0", "mkdirp": "^0.5.1", "move-concurrently": "^1.0.1", "promise-inflight": "^1.0.1", - "rimraf": "^2.6.2", + "rimraf": "^2.6.3", "ssri": "^6.0.1", "unique-filename": "^1.1.1", "y18n": "^4.0.0" @@ -10467,6 +10514,20 @@ } } }, + "glob": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, "mississippi": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", @@ -12250,25 +12311,47 @@ }, "dependencies": { "cacache": { - "version": "11.3.2", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-11.3.2.tgz", - "integrity": "sha512-E0zP4EPGDOaT2chM08Als91eYnf8Z+eH1awwwVsngUmgppfM5jjJ8l3z5vO5p5w/I3LsiXawb1sW0VY65pQABg==", + "version": "11.3.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-11.3.3.tgz", + "integrity": "sha512-p8WcneCytvzPxhDvYp31PD039vi77I12W+/KfR9S8AZbaiARFBCpsPJS+9uhWfeBfeAtW7o/4vt3MUqLkbY6nA==", "dev": true, "requires": { - "bluebird": "^3.5.3", + "bluebird": "^3.5.5", "chownr": "^1.1.1", "figgy-pudding": "^3.5.1", - "glob": "^7.1.3", + "glob": "^7.1.4", "graceful-fs": "^4.1.15", "lru-cache": "^5.1.1", "mississippi": "^3.0.0", "mkdirp": "^0.5.1", "move-concurrently": "^1.0.1", "promise-inflight": "^1.0.1", - "rimraf": "^2.6.2", + "rimraf": "^2.6.3", "ssri": "^6.0.1", "unique-filename": "^1.1.1", "y18n": "^4.0.0" + }, + "dependencies": { + "bluebird": { + "version": "3.5.5", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.5.tgz", + "integrity": "sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w==", + "dev": true + }, + "glob": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } } }, "get-stream": { @@ -12327,18 +12410,18 @@ } }, "tar": { - "version": "4.4.8", - "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.8.tgz", - "integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==", + "version": "4.4.10", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.10.tgz", + "integrity": "sha512-g2SVs5QIxvo6OLp0GudTqEf05maawKUxXru104iaayWA09551tFCTI8f1Asb4lPfkBr91k07iL4c11XO3/b0tA==", "dev": true, "requires": { "chownr": "^1.1.1", "fs-minipass": "^1.2.5", - "minipass": "^2.3.4", - "minizlib": "^1.1.1", + "minipass": "^2.3.5", + "minizlib": "^1.2.1", "mkdirp": "^0.5.0", "safe-buffer": "^5.1.2", - "yallist": "^3.0.2" + "yallist": "^3.0.3" } }, "yallist": { diff --git a/package.json b/package.json index 05ce37b1df..038bab04c8 100644 --- a/package.json +++ b/package.json @@ -81,19 +81,19 @@ "@alfresco/adf-process-services-cloud": "3.3.0", "@alfresco/adf-testing": "3.3.0", "@alfresco/js-api": "3.3.0", - "@angular/animations": "7.0.3", - "@angular/cdk": "7.0.3", - "@angular/common": "7.0.3", - "@angular/compiler": "7.0.3", - "@angular/core": "7.0.3", - "@angular/flex-layout": "^7.0.0-beta.19", - "@angular/forms": "7.0.3", - "@angular/http": "7.0.3", - "@angular/material": "7.0.3", - "@angular/material-moment-adapter": "7.0.3", - "@angular/platform-browser": "7.0.3", - "@angular/platform-browser-dynamic": "7.0.3", - "@angular/router": "7.0.3", + "@angular/animations": "^7.2.15", + "@angular/cdk": "7.3.7", + "@angular/common": "^7.2.15", + "@angular/compiler": "^7.2.15", + "@angular/core": "^7.2.15", + "@angular/flex-layout": "^7.0.0-beta.24", + "@angular/forms": "^7.2.15", + "@angular/http": "^7.2.15", + "@angular/material": "^7.3.7", + "@angular/material-moment-adapter": "^7.3.7", + "@angular/platform-browser": "^7.2.15", + "@angular/platform-browser-dynamic": "^7.2.15", + "@angular/router": "^7.2.15", "@mat-datetimepicker/core": "^2.0.1", "@mat-datetimepicker/moment": "^2.0.1", "@ngx-translate/core": "^11.0.0", @@ -121,8 +121,8 @@ "devDependencies": { "@angular-devkit/build-angular": "^0.13.4", "@angular-devkit/build-ng-packagr": "~0.10.0", - "@angular/cli": "^7.0.5", - "@angular/compiler-cli": "^7.2.7", + "@angular/cli": "^7.3.9", + "@angular/compiler-cli": "^7.2.15", "@nrwl/nx": "7.1.1", "@nrwl/schematics": "7.1.1", "@types/hammerjs": "2.0.35", From 0d6140be77a6ea00918f19ab3520b456e1eebbc1 Mon Sep 17 00:00:00 2001 From: Eugenio Romano Date: Tue, 2 Jul 2019 16:00:58 +0100 Subject: [PATCH 026/140] clean unit test (#4890) * promote use setupTestbed * fix comment using right spy and remove deprecated moment method usage * restore md icon file * remove error translation log * restore extension test --- .../name-location-cell.component.spec.ts | 15 ++-- .../file-uploading-list-row.component.spec.ts | 13 ++-- .../services/card-view-update.service.spec.ts | 13 ++-- lib/core/clipboard/clipboard.service.spec.ts | 27 ++++--- .../comments/comment-list.component.spec.ts | 8 +-- .../context-menu-holder.component.spec.ts | 37 +++++----- .../context-menu-overlay.service.spec.ts | 13 ++-- lib/core/context-menu/context-menu.spec.ts | 23 +++--- lib/core/karma.conf.js | 2 +- .../header/header.component.spec.ts | 13 ++-- .../sidebar-action-menu.component.spec.ts | 56 +++++++-------- lib/core/services/jwt-helper.service.spec.ts | 10 +-- lib/core/services/lock.service.spec.ts | 64 +++++++++-------- lib/core/services/log.service.spec.ts | 27 ++++--- .../services/notification.service.spec.ts | 72 +++++++++---------- .../tooltip/diagram-tooltip.component.spec.ts | 19 +++-- .../app-list-cloud.component.spec.ts | 22 ++---- 17 files changed, 208 insertions(+), 226 deletions(-) diff --git a/lib/content-services/content-node-selector/name-location-cell/name-location-cell.component.spec.ts b/lib/content-services/content-node-selector/name-location-cell/name-location-cell.component.spec.ts index 11acdb8841..da0ac61d83 100644 --- a/lib/content-services/content-node-selector/name-location-cell/name-location-cell.component.spec.ts +++ b/lib/content-services/content-node-selector/name-location-cell/name-location-cell.component.spec.ts @@ -15,23 +15,22 @@ * limitations under the License. */ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { NameLocationCellComponent } from './name-location-cell.component'; import { By } from '@angular/platform-browser'; import { DataRow } from '@alfresco/adf-core'; +import { setupTestBed } from '../../../core/testing/setupTestBed'; describe('NameLocationCellComponent', () => { let component: NameLocationCellComponent; let fixture: ComponentFixture; let rowData: DataRow; - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ - NameLocationCellComponent - ] - }).compileComponents(); - })); + setupTestBed({ + declarations: [ + NameLocationCellComponent + ] + }); beforeEach(() => { fixture = TestBed.createComponent(NameLocationCellComponent); diff --git a/lib/content-services/upload/components/file-uploading-list-row.component.spec.ts b/lib/content-services/upload/components/file-uploading-list-row.component.spec.ts index fe6a28043e..4b367deb88 100644 --- a/lib/content-services/upload/components/file-uploading-list-row.component.spec.ts +++ b/lib/content-services/upload/components/file-uploading-list-row.component.spec.ts @@ -19,19 +19,18 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { FileModel, CoreModule, FileUploadOptions, FileUploadStatus } from '@alfresco/adf-core'; import { UploadModule } from '../upload.module'; import { FileUploadingListRowComponent } from './file-uploading-list-row.component'; +import { setupTestBed } from '../../../core/testing/setupTestBed'; describe('FileUploadingListRowComponent', () => { let fixture: ComponentFixture; let component: FileUploadingListRowComponent; const file = new FileModel( { name: 'fake-name' }); - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [ - CoreModule.forRoot(), - UploadModule - ] - }).compileComponents(); + setupTestBed({ + imports: [ + CoreModule.forRoot(), + UploadModule + ] }); beforeEach(() => { diff --git a/lib/core/card-view/services/card-view-update.service.spec.ts b/lib/core/card-view/services/card-view-update.service.spec.ts index a572b380a2..88472cd28a 100644 --- a/lib/core/card-view/services/card-view-update.service.spec.ts +++ b/lib/core/card-view/services/card-view-update.service.spec.ts @@ -18,6 +18,7 @@ import { async, TestBed } from '@angular/core/testing'; import { CardViewBaseItemModel } from '../models/card-view-baseitem.model'; import { CardViewUpdateService, transformKeyToObject } from './card-view-update.service'; +import { setupTestBed } from '../../testing/setupTestBed'; describe('CardViewUpdateService', () => { @@ -58,13 +59,11 @@ describe('CardViewUpdateService', () => { clickable: false }; - beforeEach(async(() => { - TestBed.configureTestingModule({ - providers: [ - CardViewUpdateService - ] - }).compileComponents(); - })); + setupTestBed({ + providers: [ + CardViewUpdateService + ] + }); beforeEach(() => { cardViewUpdateService = TestBed.get(CardViewUpdateService); diff --git a/lib/core/clipboard/clipboard.service.spec.ts b/lib/core/clipboard/clipboard.service.spec.ts index 8c97214ddf..3760b5f7c9 100644 --- a/lib/core/clipboard/clipboard.service.spec.ts +++ b/lib/core/clipboard/clipboard.service.spec.ts @@ -26,26 +26,25 @@ import { AppConfigServiceMock } from '../mock/app-config.service.mock'; import { HttpClientModule } from '@angular/common/http'; import { MatSnackBarModule } from '@angular/material'; import { TranslationMock } from '@alfresco/adf-core'; +import { setupTestBed } from '../testing/setupTestBed'; describe('ClipboardService', () => { let clipboardService: ClipboardService; let notificationService: NotificationService; let inputElement; - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [ - ClipboardModule, - HttpClientModule, - MatSnackBarModule - ], - providers: [ - LogService, - { provide: TranslationService, useClass: TranslationMock }, - { provide: AppConfigService, useClass: AppConfigServiceMock }, - NotificationService - ] - }); + setupTestBed({ + imports: [ + ClipboardModule, + HttpClientModule, + MatSnackBarModule + ], + providers: [ + LogService, + { provide: TranslationService, useClass: TranslationMock }, + { provide: AppConfigService, useClass: AppConfigServiceMock }, + NotificationService + ] }); beforeEach(() => { diff --git a/lib/core/comments/comment-list.component.spec.ts b/lib/core/comments/comment-list.component.spec.ts index fd23166c78..4fc4180482 100644 --- a/lib/core/comments/comment-list.component.spec.ts +++ b/lib/core/comments/comment-list.component.spec.ts @@ -117,10 +117,10 @@ describe('CommentListComponent', () => { beforeEach(async(() => { ecmUserService = TestBed.get(EcmUserService); - spyOn(ecmUserService, 'getUserProfileImage').and.returnValue('content-user-image'); + spyOn(ecmUserService, 'getUserProfileImage').and.returnValue('alfresco-logo.svg'); peopleProcessService = TestBed.get(PeopleProcessService); - spyOn(peopleProcessService, 'getUserImage').and.returnValue('process-user-image'); + spyOn(peopleProcessService, 'getUserImage').and.returnValue('alfresco-logo.svg'); fixture = TestBed.createComponent(CommentListComponent); commentList = fixture.componentInstance; @@ -259,7 +259,7 @@ describe('CommentListComponent', () => { fixture.whenStable().then(() => { const elements = fixture.nativeElement.querySelectorAll('.adf-people-img'); expect(elements.length).toBe(1); - expect(fixture.nativeElement.getElementsByClassName('adf-people-img')[0].src).toContain('content-user-image'); + expect(fixture.nativeElement.getElementsByClassName('adf-people-img')[0].src).toContain('alfresco-logo.svg'); }); })); @@ -270,7 +270,7 @@ describe('CommentListComponent', () => { fixture.whenStable().then(() => { const elements = fixture.nativeElement.querySelectorAll('.adf-people-img'); expect(elements.length).toBe(1); - expect(fixture.nativeElement.getElementsByClassName('adf-people-img')[0].src).toContain('process-user-image'); + expect(fixture.nativeElement.getElementsByClassName('adf-people-img')[0].src).toContain('alfresco-logo.svg'); }); })); diff --git a/lib/core/context-menu/context-menu-holder.component.spec.ts b/lib/core/context-menu/context-menu-holder.component.spec.ts index e64cef1407..6206e25794 100644 --- a/lib/core/context-menu/context-menu-holder.component.spec.ts +++ b/lib/core/context-menu/context-menu-holder.component.spec.ts @@ -23,6 +23,7 @@ import { ContextMenuModule } from './context-menu.module'; import { ContextMenuService } from './context-menu.service'; import { CoreModule } from '../core.module'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { setupTestBed } from '../testing/setupTestBed'; describe('ContextMenuHolderComponent', () => { let fixture: ComponentFixture; @@ -52,25 +53,25 @@ describe('ContextMenuHolderComponent', () => { }) }; - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [ - NoopAnimationsModule, - CoreModule.forRoot(), - ContextMenuModule - ], - providers: [ - { - provide: OverlayContainer, - useValue: overlayContainer - }, - { - provide: ViewportRuler, - useValue: getViewportRect - } - ] - }); + setupTestBed({ + imports: [ + NoopAnimationsModule, + CoreModule.forRoot(), + ContextMenuModule + ], + providers: [ + { + provide: OverlayContainer, + useValue: overlayContainer + }, + { + provide: ViewportRuler, + useValue: getViewportRect + } + ] + }); + beforeEach(() => { fixture = TestBed.createComponent(ContextMenuHolderComponent); component = fixture.componentInstance; contextMenuService = TestBed.get(ContextMenuService); diff --git a/lib/core/context-menu/context-menu-overlay.service.spec.ts b/lib/core/context-menu/context-menu-overlay.service.spec.ts index 13df9279a1..6f96d4e3f9 100644 --- a/lib/core/context-menu/context-menu-overlay.service.spec.ts +++ b/lib/core/context-menu/context-menu-overlay.service.spec.ts @@ -15,12 +15,13 @@ * limitations under the License. */ -import { TestBed } from '@angular/core/testing'; import { Overlay } from '@angular/cdk/overlay'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { CoreTestingModule } from '../testing/core.testing.module'; import { ContextMenuOverlayService } from './context-menu-overlay.service'; import { Injector } from '@angular/core'; +import { setupTestBed } from '../testing/setupTestBed'; +import { TestBed } from '@angular/core/testing'; describe('ContextMenuService', () => { let contextMenuOverlayService: ContextMenuOverlayService; @@ -34,12 +35,12 @@ describe('ContextMenuService', () => { } }; - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [NoopAnimationsModule, CoreTestingModule], - providers: [ Overlay ] - }); + setupTestBed({ + imports: [NoopAnimationsModule, CoreTestingModule], + providers: [ Overlay ] + }); + beforeEach(() => { overlay = TestBed.get(Overlay); injector = TestBed.get(Injector); }); diff --git a/lib/core/context-menu/context-menu.spec.ts b/lib/core/context-menu/context-menu.spec.ts index 5a3a20bb2c..b266a830d1 100644 --- a/lib/core/context-menu/context-menu.spec.ts +++ b/lib/core/context-menu/context-menu.spec.ts @@ -20,6 +20,7 @@ import { TestBed, ComponentFixture } from '@angular/core/testing'; import { ContextMenuModule } from './context-menu.module'; import { CoreModule } from '../core.module'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { setupTestBed } from '../testing/setupTestBed'; @Component({ selector: 'adf-test-component', @@ -78,18 +79,18 @@ describe('ContextMenuDirective', () => { } ]; - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [ - CoreModule.forRoot(), - ContextMenuModule, - NoopAnimationsModule - ], - declarations: [ - TestComponent - ] - }); + setupTestBed({ + imports: [ + CoreModule.forRoot(), + ContextMenuModule, + NoopAnimationsModule + ], + declarations: [ + TestComponent + ] + }); + beforeEach(() => { fixture = TestBed.createComponent(TestComponent); fixture.componentInstance.actions = actions; fixture.detectChanges(); diff --git a/lib/core/karma.conf.js b/lib/core/karma.conf.js index a46e16d80e..47c44d0143 100644 --- a/lib/core/karma.conf.js +++ b/lib/core/karma.conf.js @@ -18,7 +18,6 @@ module.exports = function (config) { {pattern: 'node_modules/pdfjs-dist/build/pdf.worker.js.map', included: false, watched: false}, {pattern: 'node_modules/pdfjs-dist/build/pdf.worker.min.js', included: true, watched: false, served: true}, {pattern: 'node_modules/pdfjs-dist/web/pdf_viewer.js', included: true, watched: false}, - { pattern: 'node_modules/@angular/material/prebuilt-themes/indigo-pink.css', included: true, @@ -56,6 +55,7 @@ module.exports = function (config) { '/base/assets/' :'/base/lib/core/assets/', '/assets/adf-core/i18n/en.json': '/base/lib/core/i18n/en.json', '/assets/adf-core/i18n/en-GB.json': '/base/lib/core/i18n/en.json', + '/assets/adf-core/i18n/en-US.json': '/base/lib/core/i18n/en.json', '/app.config.json': '/base/lib/config/app.config.json', '/fake-test-file.pdf': '/base/lib/core/viewer/assets/fake-test-file.pdf', '/fake-test-file.txt': '/base/lib/core/viewer/assets/fake-test-file.txt', diff --git a/lib/core/layout/components/header/header.component.spec.ts b/lib/core/layout/components/header/header.component.spec.ts index 37f51524cd..3242d853ee 100644 --- a/lib/core/layout/components/header/header.component.spec.ts +++ b/lib/core/layout/components/header/header.component.spec.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import { ComponentFixture, TestBed, async } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { HeaderLayoutComponent } from './header.component'; import { setupTestBed } from '../../../testing/setupTestBed'; import { CoreTestingModule } from '../../../testing/core.testing.module'; @@ -151,13 +151,10 @@ describe('HeaderLayoutComponent', () => { }) class HeaderLayoutTesterComponent {} - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [HeaderLayoutTesterComponent], - imports: [ CoreTestingModule, LayoutModule, MaterialModule, RouterTestingModule ] - }) - .compileComponents(); - })); + setupTestBed({ + declarations: [HeaderLayoutTesterComponent], + imports: [ CoreTestingModule, LayoutModule, MaterialModule, RouterTestingModule ] + }); it('should project the provided nodes into the component', () => { const hostFixture = TestBed.createComponent(HeaderLayoutTesterComponent); diff --git a/lib/core/layout/components/sidebar-action/sidebar-action-menu.component.spec.ts b/lib/core/layout/components/sidebar-action/sidebar-action-menu.component.spec.ts index 9417e9e306..4634444800 100644 --- a/lib/core/layout/components/sidebar-action/sidebar-action-menu.component.spec.ts +++ b/lib/core/layout/components/sidebar-action/sidebar-action-menu.component.spec.ts @@ -16,7 +16,7 @@ */ import { Component } from '@angular/core'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MaterialModule } from '../../../material.module'; import { SidebarActionMenuComponent } from './sidebar-action-menu.component'; import { setupTestBed } from '../../../testing/setupTestBed'; @@ -57,23 +57,23 @@ describe('SidebarActionMenuComponent', () => { @Component({ template: ` - - arrow_drop_down -
- queue -
-
- - -
-
- ` + + arrow_drop_down +
+ queue +
+
+ + +
+
+ ` }) class CustomSidebarActionMenuComponent { title: string = 'Fake title'; @@ -85,17 +85,15 @@ describe('Custom SidebarActionMenuComponent', () => { let component: CustomSidebarActionMenuComponent; let element: HTMLElement; - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ - SidebarActionMenuComponent, - CustomSidebarActionMenuComponent - ], - imports: [ - MaterialModule - ] - }).compileComponents(); - })); + setupTestBed({ + declarations: [ + SidebarActionMenuComponent, + CustomSidebarActionMenuComponent + ], + imports: [ + MaterialModule + ] + }); beforeEach(() => { fixture = TestBed.createComponent(CustomSidebarActionMenuComponent); diff --git a/lib/core/services/jwt-helper.service.spec.ts b/lib/core/services/jwt-helper.service.spec.ts index 73858dd806..f5b0d57d71 100644 --- a/lib/core/services/jwt-helper.service.spec.ts +++ b/lib/core/services/jwt-helper.service.spec.ts @@ -15,18 +15,20 @@ * limitations under the License. */ -import { TestBed } from '@angular/core/testing'; import { JwtHelperService } from './jwt-helper.service'; import { mockToken } from './../mock/jwt-helper.service.spec'; +import { setupTestBed } from '../testing/setupTestBed'; +import { TestBed } from '@angular/core/testing'; describe('JwtHelperService', () => { let jwtHelperService: JwtHelperService; + setupTestBed({ + providers: [JwtHelperService] + }); + beforeEach(() => { - TestBed.configureTestingModule({ - providers: [JwtHelperService] - }); jwtHelperService = TestBed.get(JwtHelperService); }); diff --git a/lib/core/services/lock.service.spec.ts b/lib/core/services/lock.service.spec.ts index 53ce615a88..c9328e83b6 100644 --- a/lib/core/services/lock.service.spec.ts +++ b/lib/core/services/lock.service.spec.ts @@ -60,8 +60,10 @@ describe('PeopleProcessService', () => { isLocked: true, isFile: true, properties: - { 'cm:lockType': 'READ_ONLY_LOCK', - 'cm:lockLifetime': 'PERSISTENT' } + { + 'cm:lockType': 'READ_ONLY_LOCK', + 'cm:lockLifetime': 'PERSISTENT' + } }; const nodeReadOnlyWithExpiredDate: Node = { @@ -69,12 +71,12 @@ describe('PeopleProcessService', () => { isLocked: true, isFile: true, properties: - { - 'cm:lockType': 'WRITE_LOCK', - 'cm:lockLifetime': 'PERSISTENT', - 'cm:lockOwner': { id: 'lock-owner-user' }, - 'cm:expiryDate': moment().subtract('days', '4') - } + { + 'cm:lockType': 'WRITE_LOCK', + 'cm:lockLifetime': 'PERSISTENT', + 'cm:lockOwner': { id: 'lock-owner-user' }, + 'cm:expiryDate': moment().subtract(4, 'days') + } }; const nodeReadOnlyWithActiveExpiration: Node = { @@ -82,12 +84,12 @@ describe('PeopleProcessService', () => { isLocked: true, isFile: true, properties: - { - 'cm:lockType': 'WRITE_LOCK', - 'cm:lockLifetime': 'PERSISTENT', - 'cm:lockOwner': { id: 'lock-owner-user' }, - 'cm:expiryDate': moment().add('days', '4') - } + { + 'cm:lockType': 'WRITE_LOCK', + 'cm:lockLifetime': 'PERSISTENT', + 'cm:lockOwner': { id: 'lock-owner-user' }, + 'cm:expiryDate': moment().add(4, 'days') + } }; it('should return true when readonly lock is active', () => { @@ -109,11 +111,11 @@ describe('PeopleProcessService', () => { isLocked: true, isFile: true, properties: - { - 'cm:lockType': 'WRITE_LOCK', - 'cm:lockLifetime': 'PERSISTENT', - 'cm:lockOwner': { id: 'lock-owner-user' } - } + { + 'cm:lockType': 'WRITE_LOCK', + 'cm:lockLifetime': 'PERSISTENT', + 'cm:lockOwner': { id: 'lock-owner-user' } + } }; const nodeOwnerAllowedLockWithExpiredDate: Node = { @@ -121,12 +123,12 @@ describe('PeopleProcessService', () => { isLocked: true, isFile: true, properties: - { - 'cm:lockType': 'WRITE_LOCK', - 'cm:lockLifetime': 'PERSISTENT', - 'cm:lockOwner': { id: 'lock-owner-user' }, - 'cm:expiryDate': moment().subtract('days', '4') - } + { + 'cm:lockType': 'WRITE_LOCK', + 'cm:lockLifetime': 'PERSISTENT', + 'cm:lockOwner': { id: 'lock-owner-user' }, + 'cm:expiryDate': moment().subtract(4, 'days') + } }; const nodeOwnerAllowedLockWithActiveExpiration: Node = { @@ -134,12 +136,12 @@ describe('PeopleProcessService', () => { isLocked: true, isFile: true, properties: - { - 'cm:lockType': 'WRITE_LOCK', - 'cm:lockLifetime': 'PERSISTENT', - 'cm:lockOwner': { id: 'lock-owner-user' }, - 'cm:expiryDate': moment().add('days', '4') - } + { + 'cm:lockType': 'WRITE_LOCK', + 'cm:lockLifetime': 'PERSISTENT', + 'cm:lockOwner': { id: 'lock-owner-user' }, + 'cm:expiryDate': moment().add(4, 'days') + } }; it('should return false when the user is the lock owner', () => { diff --git a/lib/core/services/log.service.spec.ts b/lib/core/services/log.service.spec.ts index d8deda5740..c73dcd4d01 100644 --- a/lib/core/services/log.service.spec.ts +++ b/lib/core/services/log.service.spec.ts @@ -17,9 +17,10 @@ import { HttpClientModule } from '@angular/common/http'; import { Component } from '@angular/core'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { AppConfigService } from '../app-config/app-config.service'; import { LogService } from './log.service'; +import { setupTestBed } from '../testing/setupTestBed'; @Component({ template: '', @@ -61,20 +62,16 @@ describe('Log Service', () => { let providesLogComponent: ComponentFixture; let appConfigService: AppConfigService; - beforeEach(async(() => { - TestBed.configureTestingModule({ - imports: [ - HttpClientModule - ], - declarations: [ProvidesLogComponent], - providers: [ - LogService, - AppConfigService - ] - }); - - TestBed.compileComponents(); - })); + setupTestBed({ + imports: [ + HttpClientModule + ], + declarations: [ProvidesLogComponent], + providers: [ + LogService, + AppConfigService + ] + }); beforeEach(() => { appConfigService = TestBed.get(AppConfigService); diff --git a/lib/core/services/notification.service.spec.ts b/lib/core/services/notification.service.spec.ts index fba92dbce9..d0e82a4f9e 100644 --- a/lib/core/services/notification.service.spec.ts +++ b/lib/core/services/notification.service.spec.ts @@ -18,7 +18,7 @@ import { LiveAnnouncer } from '@angular/cdk/a11y'; import { OVERLAY_PROVIDERS, OverlayModule } from '@angular/cdk/overlay'; import { Component } from '@angular/core'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MatSnackBar, MatSnackBarModule, MatSnackBarConfig } from '@angular/material'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; @@ -26,6 +26,7 @@ import { NotificationService } from './notification.service'; import { TranslationMock } from '../mock/translation.service.mock'; import { TranslationService } from './translation.service'; import { HttpClientModule } from '@angular/common/http'; +import { setupTestBed } from '../testing/setupTestBed'; @Component({ template: '', @@ -37,33 +38,33 @@ class ProvidesNotificationServiceComponent { } sendMessageWithoutConfig() { - const promise = this.notificationService.openSnackMessage('Test notification', 1000); - return promise; + return this.notificationService.openSnackMessage('Test notification', 1000); } sendMessage() { - const promise = this.notificationService.openSnackMessage('Test notification', 1000); - return promise; + return this.notificationService.openSnackMessage('Test notification', 1000); } sendCustomMessage() { - const promise = this.notificationService.openSnackMessage('Test notification', new MatSnackBarConfig()); - return promise; + const matSnackBarConfig = new MatSnackBarConfig(); + matSnackBarConfig.duration = 1000; + + return this.notificationService.openSnackMessage('Test notification', matSnackBarConfig); } sendMessageActionWithoutConfig() { - const promise = this.notificationService.openSnackMessageAction('Test notification', 'TestWarn', 1000); - return promise; + return this.notificationService.openSnackMessageAction('Test notification', 'TestWarn', 1000); } sendMessageAction() { - const promise = this.notificationService.openSnackMessageAction('Test notification', 'TestWarn', 1000); - return promise; + return this.notificationService.openSnackMessageAction('Test notification', 'TestWarn', 1000); } sendCustomMessageAction() { - const promise = this.notificationService.openSnackMessageAction('Test notification', 'TestWarn', new MatSnackBarConfig()); - return promise; + const matSnackBarConfig = new MatSnackBarConfig(); + matSnackBarConfig.duration = 1000; + + return this.notificationService.openSnackMessageAction('Test notification', 'TestWarn', matSnackBarConfig); } } @@ -72,28 +73,25 @@ describe('NotificationService', () => { let fixture: ComponentFixture; let translationService: TranslationService; - beforeEach(async(() => { - TestBed.configureTestingModule({ - imports: [ - NoopAnimationsModule, - OverlayModule, - MatSnackBarModule, - HttpClientModule - ], - declarations: [ProvidesNotificationServiceComponent], - providers: [ - NotificationService, - MatSnackBar, - OVERLAY_PROVIDERS, - LiveAnnouncer, - { provide: TranslationService, useClass: TranslationMock } - ] - }); - - translationService = TestBed.get(TranslationService); - })); + setupTestBed({ + imports: [ + NoopAnimationsModule, + OverlayModule, + MatSnackBarModule, + HttpClientModule + ], + declarations: [ProvidesNotificationServiceComponent], + providers: [ + NotificationService, + MatSnackBar, + OVERLAY_PROVIDERS, + LiveAnnouncer, + { provide: TranslationService, useClass: TranslationMock } + ] + }); beforeEach(() => { + translationService = TestBed.get(TranslationService); fixture = TestBed.createComponent(ProvidesNotificationServiceComponent); fixture.detectChanges(); }); @@ -132,7 +130,7 @@ describe('NotificationService', () => { expect(document.querySelector('snack-bar-container')).not.toBeNull(); }); - it('should open a message notification bar with custom configuration', async((done) => { + it('should open a message notification bar with custom configuration', (done) => { const promise = fixture.componentInstance.sendCustomMessage(); promise.afterDismissed().subscribe(() => { done(); @@ -141,7 +139,7 @@ describe('NotificationService', () => { fixture.detectChanges(); expect(document.querySelector('snack-bar-container')).not.toBeNull(); - })); + }); it('should open a message notification bar with action', (done) => { const promise = fixture.componentInstance.sendMessageAction(); @@ -154,7 +152,7 @@ describe('NotificationService', () => { expect(document.querySelector('snack-bar-container')).not.toBeNull(); }); - it('should open a message notification bar with action and custom configuration', async((done) => { + it('should open a message notification bar with action and custom configuration', (done) => { const promise = fixture.componentInstance.sendCustomMessageAction(); promise.afterDismissed().subscribe(() => { done(); @@ -163,7 +161,7 @@ describe('NotificationService', () => { fixture.detectChanges(); expect(document.querySelector('snack-bar-container')).not.toBeNull(); - })); + }); it('should open a message notification bar with action and no custom configuration', (done) => { const promise = fixture.componentInstance.sendMessageActionWithoutConfig(); diff --git a/lib/insights/diagram/components/tooltip/diagram-tooltip.component.spec.ts b/lib/insights/diagram/components/tooltip/diagram-tooltip.component.spec.ts index 7a18134ff4..00e779d07f 100644 --- a/lib/insights/diagram/components/tooltip/diagram-tooltip.component.spec.ts +++ b/lib/insights/diagram/components/tooltip/diagram-tooltip.component.spec.ts @@ -16,9 +16,10 @@ */ import { Component } from '@angular/core'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; import { DiagramTooltipComponent } from './diagram-tooltip.component'; +import { setupTestBed } from '../../../../core/testing/setupTestBed'; @Component({ template: ` @@ -39,11 +40,9 @@ describe('DiagramTooltipComponent', () => { let component: DiagramTooltipComponent; let data; - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [DiagramTooltipComponent] - }).compileComponents(); - })); + setupTestBed({ + declarations: [DiagramTooltipComponent] + }); beforeEach(() => { fixture = TestBed.createComponent(DiagramTooltipComponent); @@ -127,11 +126,9 @@ describe('DiagramTooltipComponent', () => { let fixture: ComponentFixture; - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [DiagramTooltipComponent, TestHostComponent] - }).compileComponents(); - })); + setupTestBed({ + declarations: [DiagramTooltipComponent, TestHostComponent] + }); beforeEach(() => { fixture = TestBed.createComponent(TestHostComponent); diff --git a/lib/process-services-cloud/src/lib/app/components/app-list-cloud.component.spec.ts b/lib/process-services-cloud/src/lib/app/components/app-list-cloud.component.spec.ts index eb89b3832b..86ba05eb78 100644 --- a/lib/process-services-cloud/src/lib/app/components/app-list-cloud.component.spec.ts +++ b/lib/process-services-cloud/src/lib/app/components/app-list-cloud.component.spec.ts @@ -40,21 +40,13 @@ describe('AppListCloudComponent', () => { } }; - beforeEach(async(() => { - TestBed.configureTestingModule({ - imports: [CoreModule.forRoot(), ProcessServiceCloudTestingModule, AppListCloudModule], - providers: [ - AppsProcessCloudService - ] - }) - .overrideComponent(AppListCloudComponent, { - set: { - providers: [ - { provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock } - ] - } - }).compileComponents(); - })); + setupTestBed({ + imports: [CoreModule.forRoot(), ProcessServiceCloudTestingModule, AppListCloudModule], + providers: [ + AppsProcessCloudService, + { provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock } + ] + }); beforeEach(() => { fixture = TestBed.createComponent(AppListCloudComponent); From 4d0c98d753200445321241c127d775c29c780152 Mon Sep 17 00:00:00 2001 From: Geeta Mandakini Ayyalasomayajula <45559635+gmandakini@users.noreply.github.com> Date: Tue, 2 Jul 2019 22:00:14 +0100 Subject: [PATCH 027/140] [ADF-4697] attach content to processcloudtaskform using upload widget (#4882) * automated upload local and content file from task from upload widget. * automated upload local and content file from task from upload widget. * reverting the git ignore change * updated the app with the new process definition using the form with upload widgets * Save error screenshot * creating the processes through api call rather than through ui. and added -log to watch the travis build on process-cloud * creating the processes through api call rather than through ui. and added -log to watch the travis build on process-cloud * removed the wait till clickable, as not relevant here. * Update process-services-cloud-e2e.sh --- .../breadcrumb/breadCrumbDropdownPage.ts | 5 + .../start-task-form-cloud.e2e.ts | 303 +++++++++++++++++- e2e/resources/activiti7/candidatebaseapp.zip | Bin 5976 -> 9206 bytes .../content-node-selector-dialog.page.ts | 8 + .../core/pages/data-table-component.page.ts | 13 + .../form/widgets/attachFileWidgetCloud.ts | 94 ++++++ .../src/lib/core/pages/form/widgets/widget.ts | 5 + .../src/lib/core/pages/settings.page.ts | 17 + .../pages/task-form-cloud-component.page.ts | 5 + .../pages/task-list-cloud-component.page.ts | 4 + 10 files changed, 444 insertions(+), 10 deletions(-) create mode 100644 lib/testing/src/lib/core/pages/form/widgets/attachFileWidgetCloud.ts diff --git a/e2e/pages/adf/content-services/breadcrumb/breadCrumbDropdownPage.ts b/e2e/pages/adf/content-services/breadcrumb/breadCrumbDropdownPage.ts index 0504bed96e..caa2995796 100644 --- a/e2e/pages/adf/content-services/breadcrumb/breadCrumbDropdownPage.ts +++ b/e2e/pages/adf/content-services/breadcrumb/breadCrumbDropdownPage.ts @@ -23,6 +23,7 @@ export class BreadCrumbDropdownPage { breadCrumb = element(by.css(`adf-dropdown-breadcrumb[data-automation-id='content-node-selector-content-breadcrumb']`)); parentFolder = this.breadCrumb.element(by.css(`button[data-automation-id='dropdown-breadcrumb-trigger']`)); breadCrumbDropdown = element(by.css(`div[class*='mat-select-panel']`)); + currentFolder = this.breadCrumb.element(by.css(`div span[data-automation-id="current-folder"]`)); choosePath(pathName) { const path = this.breadCrumbDropdown.element(by.cssContainingText(`mat-option[data-automation-class='dropdown-breadcrumb-path-option'] span[class='mat-option-text']`, @@ -38,4 +39,8 @@ export class BreadCrumbDropdownPage { checkBreadCrumbDropdownIsDisplayed() { BrowserVisibility.waitUntilElementIsVisible(this.breadCrumbDropdown); } + + getTextOfCurrentFolder() { + return BrowserActions.getText(this.currentFolder); + } } diff --git a/e2e/process-services-cloud/start-task-form-cloud.e2e.ts b/e2e/process-services-cloud/start-task-form-cloud.e2e.ts index 0eb5ac0d17..e846fe22f5 100644 --- a/e2e/process-services-cloud/start-task-form-cloud.e2e.ts +++ b/e2e/process-services-cloud/start-task-form-cloud.e2e.ts @@ -28,12 +28,25 @@ import { SettingsPage, GroupIdentityService, TaskFormCloudComponent, - Widget, LocalStorageUtil, StartProcessCloudPage, TaskHeaderCloudPage, ProcessHeaderCloudPage, TasksService + Widget, + LocalStorageUtil, + StartProcessCloudPage, + TaskHeaderCloudPage, + ProcessHeaderCloudPage, + TasksService, + UploadActions, + ContentNodeSelectorDialogPage, + ProcessInstancesService, + ProcessDefinitionsService } from '@alfresco/adf-testing'; import resources = require('../util/resources'); import { StartProcessCloudConfiguration } from './config/start-process-cloud.config'; import { ProcessCloudDemoPage } from '../pages/adf/demo-shell/process-services/processCloudDemoPage'; import { ProcessDetailsCloudDemoPage } from '../pages/adf/demo-shell/process-services-cloud/processDetailsCloudDemoPage'; +import { FileModel } from '../models/ACS/fileModel'; +import { AlfrescoApiCompatibility as AlfrescoApi } from '@alfresco/js-api'; +import { AcsUserModel } from '../models/ACS/acsUserModel'; +import { BreadCrumbDropdownPage } from '../pages/adf/content-services/breadcrumb/breadCrumbDropdownPage'; describe('Start Task Form', () => { @@ -43,6 +56,8 @@ describe('Start Task Form', () => { const appListCloudComponent = new AppListCloudPage(); const tasksCloudDemoPage = new TasksCloudDemoPage(); const startTask = new StartTasksCloudPage(); + const contentNodeSelectorDialogPage = new ContentNodeSelectorDialogPage(); + const breadCrumbDropdownPage = new BreadCrumbDropdownPage(); const processDetailsCloudDemoPage = new ProcessDetailsCloudDemoPage(); const settingsPage = new SettingsPage(); const widget = new Widget(); @@ -54,18 +69,39 @@ describe('Start Task Form', () => { browser.params.config.oauth2.clientId, browser.params.config.bpmHost, browser.params.config.oauth2.host, browser.params.config.providers ); + this.alfrescoJsApi = new AlfrescoApi({ + provider: 'ECM', + hostEcm: browser.params.config.bpmHost + }); + const uploadActions = new UploadActions(this.alfrescoJsApi); + const startProcessCloudConfiguration = new StartProcessCloudConfiguration(); const startProcessCloudConfig = startProcessCloudConfiguration.getConfiguration(); const standaloneTaskName = StringUtil.generateRandomString(5); const startEventFormProcess = StringUtil.generateRandomString(5); - let testUser, groupInfo, processId, taskId; + let testUser, acsUser, groupInfo; + let processDefinitionService: ProcessDefinitionsService; + let processInstancesService: ProcessInstancesService; + let processDefinition, uploadLocalFileProcess, uploadContentFileProcess, uploadDefaultFileProcess, cancelUploadFileProcess, completeUploadFileProcess; const candidateBaseApp = resources.ACTIVITI7_APPS.CANDIDATE_BASE_APP.name; + const pdfFile = new FileModel({'name': resources.Files.ADF_DOCUMENTS.PDF.file_name}); + const pdfFileModel = new FileModel({ + 'name': resources.Files.ADF_DOCUMENTS.PDF.file_name, + 'location': resources.Files.ADF_DOCUMENTS.PDF.file_location + }); + const testFileModel = new FileModel({ + 'name': resources.Files.ADF_DOCUMENTS.TEST.file_name, + 'location': resources.Files.ADF_DOCUMENTS.TEST.file_location + }); let identityService: IdentityService; let groupIdentityService: GroupIdentityService; + const folderName = StringUtil.generateRandomString(5); + let uploadedFolder; beforeAll(async (done) => { + await apiService.login(browser.params.identityAdmin.email, browser.params.identityAdmin.password); identityService = new IdentityService(apiService); @@ -73,12 +109,58 @@ describe('Start Task Form', () => { testUser = await identityService.createIdentityUserWithRole(apiService, [identityService.ROLES.APS_USER]); groupInfo = await groupIdentityService.getGroupInfoByGroupName('hr'); await identityService.addUserToGroup(testUser.idIdentityService, groupInfo.id); - await apiService.login(testUser.email, testUser.password); - await settingsPage.setProviderBpmSso( + await apiService.login(testUser.email, testUser.password); + processDefinitionService = new ProcessDefinitionsService(apiService); + processInstancesService = new ProcessInstancesService(apiService); + processDefinition = await processDefinitionService.getProcessDefinitionByName('uploadFileProcess', candidateBaseApp); + await processInstancesService.createProcessInstance(processDefinition.entry.key, candidateBaseApp); + + uploadLocalFileProcess = await processInstancesService.createProcessInstance(processDefinition.entry.key, candidateBaseApp, { + 'name': StringUtil.generateRandomString(), + 'businessKey': StringUtil.generateRandomString() + }); + + uploadContentFileProcess = await processInstancesService.createProcessInstance(processDefinition.entry.key, candidateBaseApp, { + 'name': StringUtil.generateRandomString(), + 'businessKey': StringUtil.generateRandomString() + }); + + uploadDefaultFileProcess = await processInstancesService.createProcessInstance(processDefinition.entry.key, candidateBaseApp, { + 'name': StringUtil.generateRandomString(), + 'businessKey': StringUtil.generateRandomString() + }); + + cancelUploadFileProcess = await processInstancesService.createProcessInstance(processDefinition.entry.key, candidateBaseApp, { + 'name': StringUtil.generateRandomString(), + 'businessKey': StringUtil.generateRandomString() + }); + + completeUploadFileProcess = await processInstancesService.createProcessInstance(processDefinition.entry.key, candidateBaseApp, { + 'name': StringUtil.generateRandomString(), + 'businessKey': StringUtil.generateRandomString() + }); + + acsUser = await new AcsUserModel({ + email: testUser.email, + password: testUser.password, + id: testUser.username, + firstName: testUser.firstName, + lastName: testUser.lastName + }); + await this.alfrescoJsApi.login(browser.params.identityAdmin.email, browser.params.identityAdmin.password); + await this.alfrescoJsApi.core.peopleApi.addPerson(acsUser); + await this.alfrescoJsApi.login(acsUser.id, acsUser.password); + uploadedFolder = await uploadActions.createFolder(folderName, '-my-'); + await uploadActions.uploadFile(testFileModel.location, testFileModel.name, uploadedFolder.entry.id); + await uploadActions.uploadFile(pdfFileModel.location, pdfFileModel.name, uploadedFolder.entry.id); + + await settingsPage.setProviderEcmBpmSso( + browser.params.config.bpmHost, browser.params.config.bpmHost, browser.params.config.oauth2.host, - browser.params.config.identityHost); + browser.params.config.identityHost, + 'alfresco'); loginSSOPage.loginSSOIdentityService(testUser.email, testUser.password); await LocalStorageUtil.setConfigField('adf-cloud-start-process', JSON.stringify(startProcessCloudConfig)); done(); @@ -86,11 +168,12 @@ describe('Start Task Form', () => { afterAll(async (done) => { try { + await this.alfrescoJsApi.login(browser.params.identityAdmin.email, browser.params.identityAdmin.password); + await uploadActions.deleteFileOrFolder(uploadedFolder.entry.id); await apiService.login(testUser.email, testUser.password); const tasksService = new TasksService(apiService); - const taskID = await tasksService.getTaskId(standaloneTaskName, candidateBaseApp); - await tasksService.deleteTask(taskID, candidateBaseApp); - await apiService.login(browser.params.identityAdmin.email, browser.params.identityAdmin.password); + const standAloneTaskId = await tasksService.getTaskId(standaloneTaskName, candidateBaseApp); + await tasksService.deleteTask(standAloneTaskId, candidateBaseApp); await identityService.deleteIdentityUser(testUser.idIdentityService); } catch (error) { } @@ -154,6 +237,7 @@ describe('Start Task Form', () => { startProcessPage.selectFromProcessDropdown('processwithstarteventform'); startProcessPage.formFields().checkFormIsDisplayed(); }); + it('[C311277] Should be able to start a process with a start event form - default values', async () => { expect(widget.textWidget().getFieldValue('FirstName')).toBe('sample name'); @@ -191,10 +275,10 @@ describe('Start Task Form', () => { processCloudDemoPage.processListCloudComponent().getDataTable().selectRow('Name', startEventFormProcess); processDetailsCloudDemoPage.checkTaskIsDisplayed('StartEventFormTask'); - processId = await processHeaderCloud.getId(); + const processId = await processHeaderCloud.getId(); processDetailsCloudDemoPage.selectProcessTaskByName('StartEventFormTask'); taskFormCloudComponent.clickClaimButton(); - taskId = await taskHeaderCloudPage.getId(); + const taskId = await taskHeaderCloudPage.getId(); taskFormCloudComponent.checkCompleteButtonIsDisplayed().clickCompleteButton(); expect(tasksCloudDemoPage.getActiveFilterName()).toBe('My Tasks'); tasksCloudDemoPage.taskListCloudComponent().checkContentIsNotDisplayedById(taskId); @@ -208,4 +292,203 @@ describe('Start Task Form', () => { }); }); + + describe('Attach content to process-cloud task form using upload widget', async () => { + + beforeEach(async (done) => { + navigationBarPage.navigateToProcessServicesCloudPage(); + appListCloudComponent.checkApsContainer(); + appListCloudComponent.checkAppIsDisplayed(candidateBaseApp); + appListCloudComponent.goToApp(candidateBaseApp); + processCloudDemoPage.clickOnProcessFilters(); + processCloudDemoPage.runningProcessesFilter().clickProcessFilter(); + processCloudDemoPage.processListCloudComponent().checkProcessListIsLoaded(); + done(); + }); + + it('[C310358] Should be able to attach a file to a form from local', async () => { + processCloudDemoPage.processListCloudComponent().checkContentIsDisplayedByName(uploadLocalFileProcess.entry.name); + processCloudDemoPage.processListCloudComponent().getDataTable().selectRow('Name', uploadLocalFileProcess.entry.name); + processDetailsCloudDemoPage.checkTaskIsDisplayed('UploadFileTask'); + processDetailsCloudDemoPage.selectProcessTaskByName('UploadFileTask'); + taskFormCloudComponent.clickClaimButton(); + + const localFileWidget = widget.attachFileWidgetCloud('Attachlocalfile'); + browser.sleep(5000); + localFileWidget.attachLocalFile(pdfFile.location); + localFileWidget.checkFileIsAttached(pdfFile.name); + localFileWidget.removeFile(pdfFile.name); + localFileWidget.checkFileIsNotAttached(pdfFile.name); + }); + + it('[C311285] Should be able to attach a file to a form from acs repository', async () => { + processCloudDemoPage.processListCloudComponent().checkContentIsDisplayedByName(uploadContentFileProcess.entry.name); + processCloudDemoPage.processListCloudComponent().getDataTable().selectRow('Name', uploadContentFileProcess.entry.name); + processDetailsCloudDemoPage.checkTaskIsDisplayed('UploadFileTask'); + processDetailsCloudDemoPage.selectProcessTaskByName('UploadFileTask'); + taskFormCloudComponent.clickClaimButton(); + + const contentFileWidget = widget.attachFileWidgetCloud('Attachsinglecontentfile'); + contentFileWidget.clickAttachContentFile('Attachsinglecontentfile'); + contentNodeSelectorDialogPage.checkDialogIsDisplayed(); + contentNodeSelectorDialogPage.contentListPage().dataTablePage().doubleClickRowByContent(folderName); + contentNodeSelectorDialogPage.contentListPage().dataTablePage().waitTillContentLoaded(); + contentNodeSelectorDialogPage.contentListPage().dataTablePage().clickRowByContent(testFileModel.name); + contentNodeSelectorDialogPage.contentListPage().dataTablePage().checkRowByContentIsSelected(testFileModel.name); + + contentNodeSelectorDialogPage.clickMoveCopyButton(); + contentNodeSelectorDialogPage.checkDialogIsNotDisplayed(); + + contentFileWidget.checkFileIsAttached(testFileModel.name); + contentFileWidget.removeFile(testFileModel.name); + contentFileWidget.checkFileIsNotAttached(testFileModel.name); + contentFileWidget.checkUploadContentButtonIsDisplayed('Attachsinglecontentfile'); + }); + + it('[C311287] Content node selector default location when attaching a file to a form from acs repository', async () => { + processCloudDemoPage.processListCloudComponent().checkContentIsDisplayedByName(uploadDefaultFileProcess.entry.name); + processCloudDemoPage.processListCloudComponent().getDataTable().selectRow('Name', uploadDefaultFileProcess.entry.name); + processDetailsCloudDemoPage.checkTaskIsDisplayed('UploadFileTask'); + processDetailsCloudDemoPage.selectProcessTaskByName('UploadFileTask'); + taskFormCloudComponent.clickClaimButton(); + + const contentFileWidget = widget.attachFileWidgetCloud('Attachsinglecontentfile'); + contentFileWidget.clickAttachContentFile('Attachsinglecontentfile'); + contentNodeSelectorDialogPage.checkDialogIsDisplayed(); + expect(breadCrumbDropdownPage.getTextOfCurrentFolder()).toBe(testUser.username); + contentNodeSelectorDialogPage.contentListPage().dataTablePage().waitTillContentLoaded(); + contentNodeSelectorDialogPage.contentListPage().dataTablePage().checkRowContentIsDisplayed(folderName); + expect(contentNodeSelectorDialogPage.checkCancelButtonIsEnabled()).toBe(true); + expect(contentNodeSelectorDialogPage.checkCopyMoveButtonIsEnabled()).toBe(false); + + contentNodeSelectorDialogPage.contentListPage().dataTablePage().clickRowByContent(folderName); + contentNodeSelectorDialogPage.contentListPage().dataTablePage().checkRowByContentIsSelected(folderName); + expect(contentNodeSelectorDialogPage.checkCancelButtonIsEnabled()).toBe(true); + expect(contentNodeSelectorDialogPage.checkCopyMoveButtonIsEnabled()).toBe(false); + contentNodeSelectorDialogPage.clickCancelButton(); + contentNodeSelectorDialogPage.checkDialogIsNotDisplayed(); + }); + + it('[C311288] No file should be attached when canceling the content node selector', async () => { + processCloudDemoPage.processListCloudComponent().checkContentIsDisplayedByName(cancelUploadFileProcess.entry.name); + processCloudDemoPage.processListCloudComponent().getDataTable().selectRow('Name', cancelUploadFileProcess.entry.name); + processDetailsCloudDemoPage.checkTaskIsDisplayed('UploadFileTask'); + processDetailsCloudDemoPage.selectProcessTaskByName('UploadFileTask'); + taskFormCloudComponent.clickClaimButton(); + + const contentFileWidget = widget.attachFileWidgetCloud('Attachsinglecontentfile'); + contentFileWidget.clickAttachContentFile('Attachsinglecontentfile'); + contentNodeSelectorDialogPage.checkDialogIsDisplayed(); + contentNodeSelectorDialogPage.contentListPage().dataTablePage().waitTillContentLoaded(); + contentNodeSelectorDialogPage.contentListPage().dataTablePage().checkRowContentIsDisplayed(folderName); + contentNodeSelectorDialogPage.contentListPage().dataTablePage().doubleClickRowByContent(folderName); + contentNodeSelectorDialogPage.contentListPage().dataTablePage().waitTillContentLoaded(); + contentNodeSelectorDialogPage.contentListPage().dataTablePage().clickRowByContent(testFileModel.name); + contentNodeSelectorDialogPage.contentListPage().dataTablePage().checkRowByContentIsSelected(testFileModel.name); + + contentNodeSelectorDialogPage.clickCancelButton(); + contentNodeSelectorDialogPage.checkDialogIsNotDisplayed(); + contentFileWidget.checkFileIsNotAttached(testFileModel.name); + }); + + it('[C311289] Should be able to attach single file', async () => { + processCloudDemoPage.processListCloudComponent().checkContentIsDisplayedByName(uploadContentFileProcess.entry.name); + processCloudDemoPage.processListCloudComponent().getDataTable().selectRow('Name', uploadContentFileProcess.entry.name); + processDetailsCloudDemoPage.checkTaskIsDisplayed('UploadFileTask'); + processDetailsCloudDemoPage.selectProcessTaskByName('UploadFileTask'); + + const contentFileWidget = widget.attachFileWidgetCloud('Attachsinglecontentfile'); + contentFileWidget.clickAttachContentFile('Attachsinglecontentfile'); + contentNodeSelectorDialogPage.checkDialogIsDisplayed(); + contentNodeSelectorDialogPage.contentListPage().dataTablePage().doubleClickRowByContent(folderName); + contentNodeSelectorDialogPage.contentListPage().dataTablePage().waitTillContentLoaded(); + contentNodeSelectorDialogPage.contentListPage().dataTablePage().clickRowByContent(testFileModel.name); + contentNodeSelectorDialogPage.contentListPage().dataTablePage().checkRowByContentIsSelected(testFileModel.name); + + contentNodeSelectorDialogPage.clickMoveCopyButton(); + contentNodeSelectorDialogPage.checkDialogIsNotDisplayed(); + + contentFileWidget.checkFileIsAttached(testFileModel.name); + contentFileWidget.checkUploadContentButtonIsNotDisplayed('Attachsinglecontentfile'); + }); + + it('[C311292] Attached file is not displayed anymore after release if the form is not saved', async () => { + processCloudDemoPage.processListCloudComponent().checkContentIsDisplayedByName(uploadContentFileProcess.entry.name); + processCloudDemoPage.processListCloudComponent().getDataTable().selectRow('Name', uploadContentFileProcess.entry.name); + processDetailsCloudDemoPage.checkTaskIsDisplayed('UploadFileTask'); + processDetailsCloudDemoPage.selectProcessTaskByName('UploadFileTask'); + + const contentFileWidget = widget.attachFileWidgetCloud('Attachsinglecontentfile'); + contentFileWidget.clickAttachContentFile('Attachsinglecontentfile'); + contentNodeSelectorDialogPage.checkDialogIsDisplayed(); + contentNodeSelectorDialogPage.contentListPage().dataTablePage().doubleClickRowByContent(folderName); + contentNodeSelectorDialogPage.contentListPage().dataTablePage().waitTillContentLoaded(); + contentNodeSelectorDialogPage.contentListPage().dataTablePage().clickRowByContent(testFileModel.name); + contentNodeSelectorDialogPage.contentListPage().dataTablePage().checkRowByContentIsSelected(testFileModel.name); + + contentNodeSelectorDialogPage.clickMoveCopyButton(); + contentNodeSelectorDialogPage.checkDialogIsNotDisplayed(); + + contentFileWidget.checkFileIsAttached(testFileModel.name); + contentFileWidget.checkUploadContentButtonIsNotDisplayed('Attachsinglecontentfile'); + taskFormCloudComponent.clickReleaseButton(); + taskFormCloudComponent.clickClaimButton(); + contentFileWidget.checkFileIsNotAttached(testFileModel.name); + contentFileWidget.checkUploadContentButtonIsDisplayed('Attachsinglecontentfile'); + }); + + it('[C311293] Attached file is displayed after release if the form was saved', async () => { + processCloudDemoPage.processListCloudComponent().checkContentIsDisplayedByName(uploadContentFileProcess.entry.name); + processCloudDemoPage.processListCloudComponent().getDataTable().selectRow('Name', uploadContentFileProcess.entry.name); + processDetailsCloudDemoPage.checkTaskIsDisplayed('UploadFileTask'); + processDetailsCloudDemoPage.selectProcessTaskByName('UploadFileTask'); + + const contentFileWidget = widget.attachFileWidgetCloud('Attachsinglecontentfile'); + contentFileWidget.clickAttachContentFile('Attachsinglecontentfile'); + contentNodeSelectorDialogPage.checkDialogIsDisplayed(); + contentNodeSelectorDialogPage.contentListPage().dataTablePage().doubleClickRowByContent(folderName); + contentNodeSelectorDialogPage.contentListPage().dataTablePage().waitTillContentLoaded(); + contentNodeSelectorDialogPage.contentListPage().dataTablePage().clickRowByContent(testFileModel.name); + contentNodeSelectorDialogPage.contentListPage().dataTablePage().checkRowByContentIsSelected(testFileModel.name); + contentNodeSelectorDialogPage.clickMoveCopyButton(); + contentNodeSelectorDialogPage.checkDialogIsNotDisplayed(); + contentFileWidget.checkFileIsAttached(testFileModel.name); + contentFileWidget.checkUploadContentButtonIsNotDisplayed('Attachsinglecontentfile'); + taskFormCloudComponent.clickSaveButton(); + taskFormCloudComponent.clickReleaseButton(); + taskFormCloudComponent.clickClaimButton(); + contentFileWidget.checkFileIsAttached(testFileModel.name); + contentFileWidget.checkUploadContentButtonIsNotDisplayed('Attachsinglecontentfile'); + }); + + it('[C311295] Attached file is displayed after complete', async () => { + processCloudDemoPage.processListCloudComponent().checkContentIsDisplayedByName(completeUploadFileProcess.entry.name); + processCloudDemoPage.processListCloudComponent().getDataTable().selectRow('Name', completeUploadFileProcess.entry.name); + processDetailsCloudDemoPage.checkTaskIsDisplayed('UploadFileTask'); + processDetailsCloudDemoPage.selectProcessTaskByName('UploadFileTask'); + taskFormCloudComponent.clickClaimButton(); + + const contentFileWidget = widget.attachFileWidgetCloud('Attachsinglecontentfile'); + contentFileWidget.clickAttachContentFile('Attachsinglecontentfile'); + contentNodeSelectorDialogPage.checkDialogIsDisplayed(); + contentNodeSelectorDialogPage.contentListPage().dataTablePage().doubleClickRowByContent(folderName); + contentNodeSelectorDialogPage.contentListPage().dataTablePage().waitTillContentLoaded(); + contentNodeSelectorDialogPage.contentListPage().dataTablePage().clickRowByContent(testFileModel.name); + contentNodeSelectorDialogPage.contentListPage().dataTablePage().checkRowByContentIsSelected(testFileModel.name); + contentNodeSelectorDialogPage.clickMoveCopyButton(); + contentNodeSelectorDialogPage.checkDialogIsNotDisplayed(); + contentFileWidget.checkFileIsAttached(testFileModel.name); + contentFileWidget.checkUploadContentButtonIsNotDisplayed('Attachsinglecontentfile'); + const taskId = await taskHeaderCloudPage.getId(); + taskFormCloudComponent.checkCompleteButtonIsDisplayed().clickCompleteButton(); + expect(tasksCloudDemoPage.getActiveFilterName()).toBe('My Tasks'); + tasksCloudDemoPage.taskListCloudComponent().checkContentIsNotDisplayedById(taskId); + + tasksCloudDemoPage.completedTasksFilter().clickTaskFilter(); + tasksCloudDemoPage.taskListCloudComponent().checkContentIsDisplayedById(taskId); + tasksCloudDemoPage.taskListCloudComponent().selectRowByTaskId(taskId); + contentFileWidget.checkFileIsAttached(testFileModel.name); + contentFileWidget.checkUploadContentButtonIsNotDisplayed('Attachsinglecontentfile'); + }); + }); }); diff --git a/e2e/resources/activiti7/candidatebaseapp.zip b/e2e/resources/activiti7/candidatebaseapp.zip index 318d6be329b32b7d54aca0a95481ffc5cee71713..5df5689ba428776b1047e36b78c0eb31b04c2557 100644 GIT binary patch literal 9206 zcmb7}1yodP*T?CS?(PynN;-#l14&0q}w5+q)|#hx{>Y%LAr!*(EDD| z^dHBNK+R8Gr7o~*_)n_jEX>rcZb{+Yr!szDS>%;XlF>m1${@b&H-QUypw{ zvo0$Ne>GLNC9PbtsU&ozZe%qDVY5_L>*ld{{Y`fx+ez$zRtOvoDrHx8nFpQwjVUq2P&y zLVz?p7Zg`qIh%Z5NF^VGz@p>5#C@SnOc9E*5l(u;=@upUaaKoUgb2*QLTRU`O$-I8 z&OBBl#*{0O={0K^We0ASQkrI9AY*b;mjMNJHoSC(ntmpxTFZ;vDq-D9Uj&fgNktKV zO0O%Dy)=o+d70VX-WOt|=bN76Va1OL=V}OAxKAtYiF>5V%^^o-#$hkuD#M?0)j=f^ zv?2-k^N7E*6|AE1%zogqOZ=)h7S3eckaMlF@1u`Mo3n~6@Z3R_Iq4qx{GnP0QuCaq zNL@40c#X@f^K8i#i&i6gU84dN1CPWS#zhc%>9NkfnOOdr#p$D+F%6LK1Z&pmI30|rEG<>=9Zm zn!oZQH5eCeEOz{2JctR)&39c5TAb2y*Hk5}eO?2d7D^0I0VSi9FoE~pDQCZuUyK{) zeosMtHfIF_*$HPN4qM+$qwjgbo;UNz2=0HIMrt+|*7`_Uvcrs@mKa;6bkaH;vma^*EuhBY5Lq)CIoFsG%`cfzT0h;yVW2l&aeo zS-6I4TNwR_#@&g?NZH#+fm6(T@b7I`i{6MzjCo%J`25sa=1dZG#u*3Iv@463Eg6nU z>#A0>hBakIO$)3ZlAcfws3gv|)5WG4bE3D}!M!}PDvuA%2k4!GF=iF~Xv$Wz+zpN- zFYRS1(~A@IxO$xiHE`afOvC~QQ_Ash5j~RRDHGh#xEJG1El7P=i$9~|gtLw1RQoxD zPfLfwG4(oWPhS{teBIb9vGp0B({HajozJJVH47$;kXoE+Nt-z3I`&-ENek(97&VF^ z+Nf95rxrG!?uQZRKg8`#my$3jt4WjQ*w|Scg6!=<|3B7n|29(J%G$vcWGDU~9zV9TcC=CY>6iuN;sCO; zH?y{~{{bSp@F(akl$cVx99z*q@z+jMgbCcoaIj%rS+LOZkI;$VB|VrlVSUB`No4cBw`UGP5nJ|H;|sbEAbU$#=*{J{|#(bSU$Y=&2sR;vL;&y*e`_n^9Sn`ax1LaY z)NiYOaiqTwhm!*HN~s+>z@=5}dBr0_Q3YZD0mZ;sr4-jRmGId9VA3r^hj*?p{_}HY z*~)$nQ?z93qtr7zcy1BTnWr$P*e#Z5t-`)fjTFncJPHeVZDp?sUrBm>{Fv9m$b-C~MX^}ZA z77se6ckGmS)++>S0uAY-eTmgJfE>hI6EePFPp&Qn0v`i$t1tpyyhVlZg0XCr)a<G2ibG&8oZRT+T>WvTPfFyGN2aTuOxyc|3Tp5`*UwL)dAke#MYy#zf~arqlI| zW0-OSSzaTjxIonDgl=a%5jIORe}8bI?*96BCG!s!q~8%75*ur4TDRj(?jMnMyP1-e zYKx}qz@QgwLS8AA5S0A$Lc0I^ zLbA6vGl9IA{t*z(=zf%#64#*q=w~Phjod=xBdnqtsEAJ&?Mw|%oil|#@FXSSy!3-! zEMx6to~EwX?N-QmRIJqQqW`r5ds1Lj&bw8^+?3LjCVuSHODJs^2scrT(oL!^MtW^e z*Q6-6Sc=nXGxjFXD~O|^w&7Abb$mLb|)8T?@H$u3VPLb?6ZEL zK+ol|aOgv}7bbO+Nqt{RDyld=?G0-5s<0WGvo5xH;IcBtz*DIcJkcpJ_6l~j1C1Jz z_g2VMqzooid*d^iL~XZmh>u6s@&$U8tsxmTbSXhvw+Jx1Y$8c6eg+2w&0al@tN0COwbQ9{rlTtAf*9O9O8deuyKzQ%On8 z-o75AEPlorT)_QM7e=WD>_?&OT@tqGwh^-ICPXZ{ZZEE7mFr}P4aotfYW>NP#Sv3g z{KU^9GAAN%O#6;{#wLBO>(%vIie}XDy2KBGZA(G8dfIliX58A)y2hqe^W7SCa8zx% zF5mJe_Q*`>N9f-yi~uimJnOX=5>SU2+H~R1Yl-F2EF=r@wl@jP!PIleiVF5V6j+mD zUJ(7l@&G>LYOKGMSiV<*qgz#Fo=%kBr<%^1+NL`AfJ5B!rNF(H6X(_7QkNuyQ{-l< zDG+?{C-G3nkQiWZbrXo!x_~>Ps-(tbjari7G$3XCUGKzb;Ud4Q{A8G2V20r!ig z4UJElD_~0jT}l*Lc6M#iw%$~&tD(p*>)1R`L}K`4oh~0)D{mstSDx(yFTRmUVw_kl z(H$jmAY%8ONsXs2ZYAJ|yyaBK11X?20Jr!csV|IAWOA=?m{LmGR>0bmnutte{b0Dbt+q1_aJ`= z@@~?!y}SG2&g7sq;PJ%!wvLJLo`BJN)Yg;B9Z_`41!hxMZ#s|PA|BI4fzpMsYhPY= zR8J@3_f}nMZ+lap&Nb*>r0!n-c)4bBQ5GIRm;j4<7ZX^2TSR|vo-5b8EuJ~o%%l^3p^$B}<5U>G`~oITVW z(bFg54eTPgp+me_$+`z5?C3k`!1V8l-D1Rh^(m`GHe8S0rxLChwV2O>ePngk!Pq-l zmJg0tI3i?(- z<$WoX+B^Dk$pX3L+kQ!gMxg$tb>x8wVFsotFEy?NCfT#u6J}(D*NbR4btau?%^LLj zv{9E6t!w9r!qVihu6yQ_4w_Woi=q_{!BOO3l;T44b35OJg6w*@UcjJtfjbgQa2Sq5Bkb{0viryH*?x@G)RojKUvbz>2_AaY~k| z`mD0U0sSvt+5=D1Kn~9iM?QyVg+)IK?0LDaCTuQ8qM=@m@d&9&w4$-3*cX6dDp&LJ zJB1ET(Y&l0wXs2wSX22bbf{OZZ9H=*iadXkB~}mPvl616d<=YO*5gEmKv39yx1XPF|m3#Z7>1L(@RpO(Y{Sn zP1pwa>mo-Bil@0-?2)}CG>tv}&v5-dEnp?%yW(;%nV)1K#eHA`5tw6A1z7itF&ZsC zM9UqaLD9+1D_P@%k`Y(@jt>%ncG%K?xK$QvP|ojci|;CdjCl;JUNE)xQHJl>l#*bo z?8O^=@5ykrZf<^R6t!dBoLQi2-lY@mCjO+xWqW&5!56*kyu(4x`k^4cQw(9v4a-y0 z{0s2bI>wH-GZ|;Ub>PN&&uazVSs@g&#AXF_Cz-H`!$queL>2pYc87=qGEOUt3KiyQ zwIdIhcZ0^pX zyHh7T{O?Og%^qZThgkRv33Qp0@dJh5EDVGrP9>1_@D+M5&Hd1c7vlA168tCM_$~yOo-kz^LZjAUC- zRu^6%PQjx?d5%}?diN5@9dr`y5}ECFnM>M3+ib60tni1~!mx-D1wCqGz&}sPZDw0u zRzvbMT!;NMVT3#?T`QGS7wG;Iu-{Sle~N{X6Tf}>m`Q3gHd)Lr9OOjQhZV?Cz#d)m_iHc^!2h7R$cZLrj>I` z65dq{gLGkY!7J6^1m9gJGgqS#bQlJK3{NVnm${PUi*qhhC>nU$o-Y2|bT%3Fp8+Ly zqtt2>DEeY8z&wPj6dhzXw3&^icAjr4RI*4rfXcYf4$DkfdFw!b$@j=m!Zyy!G7Sh0 z55yNglzI*^imQ4Sqpp>|mt!w0)Kz-36hqcMmPB!(BvY{C$NFAj~?Ua7ftHN!@j}z!m&U%Bsg7#gx|m#=e0%)XAxdc)`#Uyx0p z^{Z?;Gj9PLo9*Ch8SCcM4mFN5%$tQvr+L+J)_6JR`enY|Ga0{HF#cJXC`3nKpM-$m z6#1?N!}%Ks{wh&8n>m=;-&8h1HjpcS~1wm z5Mbe!17GS|Ejl^bck9{s^dxrn#?A`l&uRhc^y!v+MD3P5G;~#!s%B04VPhiy;lXxq z%Z3*u`1m_{@H^-JF}>fQa3d2iJ%7ps9%L9M$IQafs+kv45GK$k(W-yWEmNJ}9p`4J zZBh}fx2{U!wD0TD*R!eUS?yu~!V#P)ak&SAMal88`eHKA&+YQhHhb4!U;@JIO zYS}EpP+$_3a!i{iF{#9|Cd%Y(w(p1D8Qel-AZu{LE0uS>pcfu`+a^)5Ww|yTq2Ge> zqcF>MRs9(~-i6jJlVmN%87=0aFAu5@<NH4tAl?oKPq<{WxV`{S`QE{j_kCD!g6|(ajLkR>L|^ z_+;M2(iD*Gn4Y%MEcNuk&M@gp#$M28QVyxF+E3+#sR!vS>O9g^fnWDF6qLtse24o? zI4HUq)$OmV3J!u9@6XeMLblDXva6b~o~(fQfMmmq49D-wNc~d3C{3=T$#^ELgdCo* z491o2equE`m6Ai4QVT~PFU>_CzQ*7`p03X}oSPvCUz$X|n&G8aE;rBf6A))w_%`fE zC17CV?W+#*oj6{^xAXWsVfo&R!~u7Pc-q$CF=xJ8h*522gtV1dMDz#YxI_Izr%nQy zuY#|7D`rzKE~391j%s;pJpNgJxJPTAgaZo&wRWehc<>ud9RIFr|Ffn*Y5lp)z>?*n zu8lvQ9Pnu7E|HXW2tm+%d97<1xr@eW?^DeNWo?@m>mR$m&YW91CKMo69AFzPrm-2P zZY-Qc&fiIqH%Ux!((RZGMyla1JHQ^Cy%byWE|og$!;OxlYPPAQ$z!=u6wjh2g2p3d zf0iJCDX0T(kbooZBnbW8DcvGRBcvYr=0_1i)Qcf8QUW&)xEZZ5JXxZtX=dG7hV~61 z(O@{|;)pXHI=XVBd$!bbSE%D84OUxcH~N`-Zmpi+kuRUGX!iY8|J*2yv~(*+0_}d* zk}-{FP4Y}Cxg=nwn5ygBJKdd+slDR zUNdvWdx7-QCU0LeeyZ#R+aS6MhJYoalr5$OXGIFI>HSr^*}r--$2)(QZ|QrY<6(Y) zB%E6D?2zMw1JP~1NB+GmKrMXSYQN6FQ8BRR0tTa~uZ9f)H`0RzI=yD%G`76gi@ z5ShLt;L8&+<6RsNtKfGLTU3PN>~>rvBb+J2e8k%SAXr~-W_Yb6f93vwrim+6f6VS- zFXD<{M6sM{0R3owf=iyjaq>D+k`l&S*qs5ofvlW_uqZotK(tq{YZNkFn#Z(C-etPS z$k4;}6x*h`LHd;Mp5COE;s`of_b0aWCYWJ((UiBptYK03VuV!Jv-B~<4vdg7>hpG_ zVWSs}zc5`O>358v?RgMhSMVGQ&&hhGHiP1VFgw;MY7`7KBq|Ft+o)93bRU>TFnSNr zK*M(E&S3C1hjSUJ1=BXqqOq!E3DXGM$j9X^TkvfzRe&U{JoNf~sxp};JI^Q9zYrSo zcep&1kx+Ewp|p@cNNl}uNUD~!P8upILK3ig;<9<1NET8rh|g04kU9J=CBjpMlo4RJ zP!qI`m?bc=9RF&=>4`c;pl5>4>BhrdnTQon>HQq%4hfT7zN;W&;%l#rz_FG5d_f`p zmDZZC25SZSr8-Hj*L8#+NJsjUZ1_@b7{b;cv;F$O!L!e=Bp?JJJT=Ekh5g;e|3IG(6@KYH#+#2jbi;* zzqfYDf9m}|W4^t)_~Xf8|C{eSLcT5PZ+0fXY!G{2BLc8T0!+X~h4Z zE^tTixAnx05c*}z#J7F_t1S96=-UXrkt4tC`fkU+1q=TJk62JxQ0@>ufXHvW{2zIG BA#(r# literal 5976 zcmb_g2{_d2+n!-C_I+QDB3le143d4P$-c`nBFhY8ED^G0%f42M5)!g6p|V7l24lFg;{A^Z0WcjBFg}CeuQb>X7ZU`WIIx(5orj}~qn$V07zOu& z{bvt|J<{Fdgc!un-3^U|0D$AVX|VmhevwgPt%B8ySn5QGnqaQ* z&D@MR%K?oMQ)WW~*RH}u{fR`{xZXbXDB-f=3Skl#I%=$ZjURCmx-!tO%4)p)L(+md z_363T0HY3&oPKqkS7D3QxKHs*>h&}I#B^>3?L7_0BH5*btXEPOOHmh#S_?N##H`glbbwy!>!L&Vyv!gOa2R8U>pCL3+3i4Ff2Rh0)6|OoIu#1+Rl-6fVoJ z?JPc;Ad0qp)dk+>kC~#l1X-+efxWquZm@aJG-EO`VTa28@j_m&v7w>omxN3ww;MDl zBveZVckDfya~=0ZHLj+FPxVxx0u}#efIa%lnNr9X0z6!3AGW0A@8M-=4>&)D3j`qj z3%H2D{k-8GC>MkW3UUF3@IWIa06<8Yrs>Zyb2yE&TaGG(n+DL|;6_Qhd}TbUG*X#c z(ayfE!Cv}7CdnHrF74;+HR|8Hb8?e&?_waK+Gr4cUd5OgcZhGtpuIljj>KGO zwZ;uLP-%5)CdSsG5#Q(^S{*Ycd%R%3_xy3ALI8>HHLBr-KqJ3L459#_2PjkUJ5Bx| zrNqP%ab1k%(&7WfAbw&3^B8R*v{r%E2NRK!D(RUQ5HrdQdwT5d7AuN0BTuio>FL^L zAZ8OnWjeC$eE)-UyE$FJlN&6Gcf|F1ZyWK&(;Sl(H;`f!EHOj6R>YjLsl zv1RAv>ZdQmq6Q<%Ml*TM0o?*Hp7kAoP>j8SE@RsX3i>aP9$QW)s%xGXXBKF$iZ*C$ zs^cXy;yxo7DNVh8dWJFIP9~jlF&JX%JE_@%p|lP{ya6k4R$BQSeN;ocShjMMmxPDw zm4J4w5kCbHYfK0qj0v_xsFqp)9$2fuHisWeygw+}Inz@j^^q{6fvN%oeew;jY(1&qA%j-3Uwwlg=pD6V12R zxRoBmwQedHNo&>yRu{-HJ6EQ0C(Rlq)l~5|`>Q(S20EAd@@;d|-_MpeE*k!Tm0r-X za88cpPNHlu8yKtdHsLU_UKnq5B-iXF*-Lu(ny6l_rpxtxe z7=g3icEhd;BsP^2E&)B?uTf#y2Tj*=#Z1|JX++d74NK@ccs*M!ve{6N0y9;94yS&$ z-Ew_0vcMLHIcZ#;zzcGg@08FD?w?bV9wf}8YOfBxl~W|LQrIr-Gq0XiG|yJMDo`D! zo@t4BS#d4!=}Yt4tCLR^+|KG+=2@hr>$F|a>3+RA)3$cOJf&DA)r2>wVMPvFLmaMg z<*bcXSwPB+c+yuYt};E=wYR|Tbm(yw+FX+S6DmjGN&-bM%Zv%HcukE!i(}5bP@FFG zDDakjTZMJOSY|JG%7e4nzjAxOIO34YU*Im_?c?%wF}ze$@r?e28Lq$neHYy0@|3~m zTksHYt)k6c%KT@Ar0t6n9+l|aH(j^J}SS!)9=P8t!M%_q~K9f}A`%9Yoh^QUQ+ z8_44o8kv}bfq0m`p2xLJ?D0tz>Ca#$3Xu5~%nmaH8Yu|?dNbkpe}T2bd7RzidyGN> zc=FggpOkFq8G@$Bjs`52N%O@6+4x!(L{03a74NF1HdB%oj_D*nN&EVpNyHV|Xy)FF zbCjS@<1)jE_Cy2cF;*6@?j3nm4!z>{m2H|3-zt$@QO&Ozg%==lpjA5*%H_NV9R58n z5d;7Oo>ye-_xIx;H!K&Q58yxU^ZFqwvn5i9D)n{wg$ME?|hbcHlm{C{@7jIkXErN8b(7FUNKNih?Zg-Jq2mPk)zL@>O+B7C2dmkA$$e;&?TB90x^c$ zs_4`}%pi$neDjL-*`lzkDPUR*`Ng5yq6GewXbm^CW$DX@)JTct%cSFvB#wStgNJUHV%(Ji=y z73&b6o^xspcXElWb#krInn?Xi)zL1$&-@&4X$#RpQ2&+y=cm+^8P??yf~~u3#omsQ z<09|6pO1tX)HWKP=>~8ZNQJyuq|aaWh?oOQD`i9tB`pU05lj_(%2Z(dE9Hlgfrz5x zSV4L_KVRj~7s^hQI*97b!*2()B}6G0ltGp}JWg4n-b}ISboU6jNStX@AOZ~y2>y<8wRPPWAGvhau)M9Jhia;T_$lu&+N%1bBiMuPy{Od$|bMv=Al znqVNg7p`7z)^N^`GWBF`vqkDli&pi80qFC}V4>r>0UYa?4+6c>*2|LbBMSm4eN^3d z$yK*GE6%JGimyc5Bz*N(nv>zy5ZzE13X|%~*U6>`YQu7=>H8U(`Z(5Re&{&aBJ0UX z1nuu8GD`PUS9BNdh&CUF6BLIjKR%ixc^gF_)Uegd-hBsgLhz3UfGotxc=N|&pVXF93=aVf;bpH^7hcmt<7vcqkFjFfxjh&eI&g3h< z)+QS27daE7IwggiwB^NhEPPcqu8tk_vVX*hOZD||F+3aK9m+I}_`q5JZ1Oe*nrOsE zTX*ik)M)Q$)6$KOFo3^ux##DVPXdN!`OwgsrB4pB4G11m zIY!xCn`y8@T$a9N)HtzcxSEnA2bg>f(lGD}ca{^$^=DqbzIRX7{a$KeJArjYC1C%&F1o_~XRx#;{Q zu!yglXohT+NbxvT#MTRM^(_{gv9~PBB#)JI)C_8LmTY)#WBik(YHCC!=^gJQes9M0xhGiOLs>YA9GQj)&-Tz*QP*s zQ#w_27l)Ue?CKkk^L3``{Dr*Y4~5D6+g-NeHY}BP4MdpIr-RJn}^{>hrV~2)J+Ap|iWM(vYT1*iV z1-nk(SoC>6z@}CeEo|c7>EGt2hoa7YXA4hf>L{Wxm+wZk-!1xAT%RJ1KPjg&=>s9oc@CPE~Ozh z%%z5tw<4H1e(@7mAEi^7H&G{R0FKXRA!g=b2!{MfZIEJqf3@yRtA1a|gqr>Eai`2% zqSy0oFW-|wLY&wVY^xvPX-D81q1LZyhY`R9`0oV7-VOz~Ln8ljeQW?=^QIj7yWie7 z>C)-ZGp;bu*6-2j)YTH!($f~!*Ao_iVb2QbhzMbNdI_~HgoX(I9OUfeHPs63nKi*b z4I7Yv0r2fyXz%a&Gw^evZ)5*ZzcVF*>3qA?K?97xTkMD4-pl=^{@c<2*No_JAqNdA z-f!KNN0Gq-j8IO-!1I#$Mt{W?!zS>q&YmV?nf*w;NP$; VOoxaVzX;jhLzoBvV4}mn`yWi6VHyAc diff --git a/lib/testing/src/lib/content-services/dialog/content-node-selector-dialog.page.ts b/lib/testing/src/lib/content-services/dialog/content-node-selector-dialog.page.ts index 132e75be19..e4a80e3b95 100644 --- a/lib/testing/src/lib/content-services/dialog/content-node-selector-dialog.page.ts +++ b/lib/testing/src/lib/content-services/dialog/content-node-selector-dialog.page.ts @@ -65,6 +65,14 @@ export class ContentNodeSelectorDialogPage { return BrowserActions.click(this.cancelButton); } + checkCancelButtonIsEnabled() { + return this.cancelButton.isEnabled(); + } + + checkCopyMoveButtonIsEnabled() { + return this.moveCopyButton.isEnabled(); + } + checkMoveCopyButtonIsDisplayed() { BrowserVisibility.waitUntilElementIsVisible(this.moveCopyButton); } diff --git a/lib/testing/src/lib/core/pages/data-table-component.page.ts b/lib/testing/src/lib/core/pages/data-table-component.page.ts index f3a4487f13..fb974a02ec 100644 --- a/lib/testing/src/lib/core/pages/data-table-component.page.ts +++ b/lib/testing/src/lib/core/pages/data-table-component.page.ts @@ -329,6 +329,19 @@ export class DataTableComponentPage { BrowserActions.click(resultElement); } + checkRowContentIsDisplayed(content) { + const resultElement = this.rootElement.all(by.css(`div[data-automation-id='${content}']`)).first(); + BrowserVisibility.waitUntilElementIsVisible(resultElement); + return this; + } + + doubleClickRowByContent(name) { + const resultElement = this.rootElement.all(by.css(`div[data-automation-id='${name}']`)).first(); + BrowserActions.click(resultElement); + browser.actions().sendKeys(protractor.Key.ENTER).perform(); + return this; + } + getCopyContentTooltip() { return BrowserActions.getText(this.copyColumnTooltip); } diff --git a/lib/testing/src/lib/core/pages/form/widgets/attachFileWidgetCloud.ts b/lib/testing/src/lib/core/pages/form/widgets/attachFileWidgetCloud.ts new file mode 100644 index 0000000000..1cbbb2385a --- /dev/null +++ b/lib/testing/src/lib/core/pages/form/widgets/attachFileWidgetCloud.ts @@ -0,0 +1,94 @@ +/*! + * @license + * Copyright 2019 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { FormFields } from '../formFields'; +import { BrowserVisibility, BrowserActions } from '../../../utils/public-api'; +import * as remote from 'selenium-webdriver/remote'; +import { element, by, browser, ElementFinder } from 'protractor'; + +export class AttachFileWidgetCloud { + + widget: ElementFinder; + constructor(fieldId: string) { + this.widget = this.formFields.getWidget(fieldId); + } + + formFields = new FormFields(); + contentButton = element(by.css('button[id="attach-Alfresco Content"]')); + filesListLocator = by.css('div[id="adf-attach-widget-readonly-list"]'); + + attachLocalFile(fileLocation: string) { + browser.setFileDetector(new remote.FileDetector()); + const uploadButton = this.widget.element(by.css(`a input`)); + BrowserVisibility.waitUntilElementIsVisible(uploadButton); + uploadButton.sendKeys(browser.params.rootPath + '/e2e' + fileLocation); + BrowserVisibility.waitUntilElementIsVisible(uploadButton); + return this; + } + + clickAttachContentFile(fileId: string) { + const uploadButton = this.widget.element(by.css(`button[id=${fileId}]`)); + BrowserActions.click(uploadButton); + BrowserActions.click(this.contentButton); + + } + + checkUploadContentButtonIsDisplayed(fileId: string) { + const uploadButton = this.widget.element(by.css(`button[id=${fileId}]`)); + BrowserVisibility.waitUntilElementIsVisible(uploadButton); + return this; + } + + checkUploadContentButtonIsNotDisplayed(fileId: string) { + const uploadButton = this.widget.element(by.css(`button[id=${fileId}]`)); + BrowserVisibility.waitUntilElementIsNotVisible(uploadButton); + return this; + } + + checkFileIsAttached(name) { + const fileAttached = this.widget.element(this.filesListLocator).element(by.cssContainingText('mat-list-item span ', name)); + BrowserVisibility.waitUntilElementIsVisible(fileAttached); + return this; + } + + checkFileIsNotAttached(name) { + const fileAttached = this.widget.element(this.filesListLocator).element(by.cssContainingText('mat-list-item span ', name)); + BrowserVisibility.waitUntilElementIsNotVisible(fileAttached); + return this; + } + + async getFileId(name: string) { + const fileAttached = this.widget.element(this.filesListLocator).element(by.cssContainingText('mat-list-item span ', name)); + BrowserVisibility.waitUntilElementIsVisible(fileAttached); + const fileId = await fileAttached.getAttribute('id'); + return fileId; + } + + async removeFile(fileName: string) { + const fileId = await this.getFileId(fileName); + const deleteButton = this.widget.element(by.css(`button[id='${fileId}-remove']`)); + BrowserActions.click(deleteButton); + return this; + } + + viewFile(name) { + const fileView = element(this.filesListLocator).element(by.cssContainingText('mat-list-item span ', name)); + BrowserActions.click(fileView); + browser.actions().doubleClick(fileView).perform(); + return this; + } +} diff --git a/lib/testing/src/lib/core/pages/form/widgets/widget.ts b/lib/testing/src/lib/core/pages/form/widgets/widget.ts index 8b4acb880a..38c151f3a1 100644 --- a/lib/testing/src/lib/core/pages/form/widgets/widget.ts +++ b/lib/testing/src/lib/core/pages/form/widgets/widget.ts @@ -33,6 +33,7 @@ import { AmountWidget } from './amountWidget'; import { ContainerWidget } from './containerWidget'; import { PeopleWidget } from './peopleWidget'; import { DocumentWidget } from './documentWidget'; +import { AttachFileWidgetCloud } from './attachFileWidgetCloud'; export class Widget { @@ -52,6 +53,10 @@ export class Widget { return new AttachFileWidget(); } + attachFileWidgetCloud(fieldId: string) { + return new AttachFileWidgetCloud(fieldId); + } + displayValueWidget() { return new DisplayValueWidget(); } diff --git a/lib/testing/src/lib/core/pages/settings.page.ts b/lib/testing/src/lib/core/pages/settings.page.ts index 3451afb103..685cd545d7 100644 --- a/lib/testing/src/lib/core/pages/settings.page.ts +++ b/lib/testing/src/lib/core/pages/settings.page.ts @@ -169,6 +169,23 @@ export class SettingsPage { await browser.sleep(1000); } + async setProviderEcmBpmSso(contentServicesURL: string, processServiceURL, authHost, identityHost, clientId: string, silentLogin = true, implicitFlow = true) { + await this.goToSettingsPage(); + this.setProvider(this.ecmAndBpm.option, this.ecmAndBpm.text); + BrowserVisibility.waitUntilElementIsVisible(this.bpmText); + BrowserVisibility.waitUntilElementIsVisible(this.ecmText); + this.clickSsoRadioButton(); + this.setClientId(clientId); + this.setContentServicesURL(contentServicesURL); + this.setProcessServicesURL(processServiceURL); + this.setAuthHost(authHost); + this.setIdentityHost(identityHost); + this.setSilentLogin(silentLogin); + this.setImplicitFlow(implicitFlow); + await this.clickApply(); + await browser.sleep(1000); + } + async setLogoutUrl(logoutUrl) { BrowserVisibility.waitUntilElementIsPresent(this.logoutUrlText); this.logoutUrlText.clear(); diff --git a/lib/testing/src/lib/process-services-cloud/pages/task-form-cloud-component.page.ts b/lib/testing/src/lib/process-services-cloud/pages/task-form-cloud-component.page.ts index 90fe1c809a..9b468c2e6a 100644 --- a/lib/testing/src/lib/process-services-cloud/pages/task-form-cloud-component.page.ts +++ b/lib/testing/src/lib/process-services-cloud/pages/task-form-cloud-component.page.ts @@ -54,6 +54,11 @@ export class TaskFormCloudComponent { return this; } + clickReleaseButton() { + BrowserActions.click(this.releaseButton); + return this; + } + formFields() { return new FormFields(); } diff --git a/lib/testing/src/lib/process-services-cloud/pages/task-list-cloud-component.page.ts b/lib/testing/src/lib/process-services-cloud/pages/task-list-cloud-component.page.ts index 8fae156284..13b92a2a88 100644 --- a/lib/testing/src/lib/process-services-cloud/pages/task-list-cloud-component.page.ts +++ b/lib/testing/src/lib/process-services-cloud/pages/task-list-cloud-component.page.ts @@ -79,6 +79,10 @@ export class TaskListCloudComponentPage { return this.dataTable.selectRow(column.name, taskName); } + selectRowByTaskId(taskId: string) { + return this.dataTable.selectRow(column.id, taskId); + } + getRow(taskName) { return this.dataTable.getCellElementByValue(column.name, taskName); } From e03799e0382955f486380092fb1512bd75aceca2 Mon Sep 17 00:00:00 2001 From: davidcanonieto Date: Tue, 2 Jul 2019 22:05:11 +0100 Subject: [PATCH 028/140] [ADF-4721] Fix Material Datetime Picker date format (#4893) --- demo-shell/src/app.config.json | 2 +- .../card-view-dateitem/card-view-dateitem.component.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/demo-shell/src/app.config.json b/demo-shell/src/app.config.json index 8686c4b995..b770b4ad60 100644 --- a/demo-shell/src/app.config.json +++ b/demo-shell/src/app.config.json @@ -441,7 +441,7 @@ "dateValues":{ "defaultDateFormat": "mediumDate", "defaultDateTimeFormat": "MMM d, y, H:mm", - "defaultLocale": "en-US" + "defaultLocale": "en" }, "files": { "excluded": [ diff --git a/lib/core/card-view/components/card-view-dateitem/card-view-dateitem.component.ts b/lib/core/card-view/components/card-view-dateitem/card-view-dateitem.component.ts index cbfd3df618..f7fde2fe35 100644 --- a/lib/core/card-view/components/card-view-dateitem/card-view-dateitem.component.ts +++ b/lib/core/card-view/components/card-view-dateitem/card-view-dateitem.component.ts @@ -68,7 +68,7 @@ export class CardViewDateItemComponent implements OnInit { this.dateAdapter.setLocale(locale); }); - ( this.dateAdapter).overrideDisplayFormat = this.dateFormat; + ( this.dateAdapter).overrideDisplayFormat = 'MMM DD'; if (this.property.value) { this.valueDate = moment(this.property.value, this.dateFormat); From a13196a83696c92a6b04eeb73713ac9a9be97f76 Mon Sep 17 00:00:00 2001 From: Suzana Dirla Date: Wed, 3 Jul 2019 11:48:14 +0300 Subject: [PATCH 029/140] [ADF-4715][ADF-4717] fix process-filter-results random failing tests (#4888) * [ADF-4715] a process never has CREATED status * [ADF-4717] clean up in afterAll * check mediumDate format * check mediumDate format * show more log data * Revert "show more log data" This reverts commit a19c629 --- .../metadata/metadata-smoke-tests.e2e.ts | 2 +- e2e/process-services-cloud/process-filter-results.e2e.ts | 9 +++++++-- e2e/process-services/process-instance-details.e2e.ts | 2 +- e2e/process-services/task-details.e2e.ts | 2 +- e2e/util/constants.js | 2 +- .../components/edit-process-filter-cloud.component.ts | 1 - .../actions/process-instances.service.ts | 8 ++++---- 7 files changed, 15 insertions(+), 11 deletions(-) diff --git a/e2e/content-services/metadata/metadata-smoke-tests.e2e.ts b/e2e/content-services/metadata/metadata-smoke-tests.e2e.ts index 1ff6ca98d5..45bf0b26b4 100644 --- a/e2e/content-services/metadata/metadata-smoke-tests.e2e.ts +++ b/e2e/content-services/metadata/metadata-smoke-tests.e2e.ts @@ -33,7 +33,7 @@ import { NavigationBarPage } from '../../pages/adf/navigationBarPage'; describe('Metadata component', () => { const METADATA = { - DATA_FORMAT: 'mmm dd, yyyy', + DATA_FORMAT: 'mmm d, yyyy', TITLE: 'Details', COMMENTS_TAB: 'COMMENTS', PROPERTY_TAB: 'PROPERTIES', diff --git a/e2e/process-services-cloud/process-filter-results.e2e.ts b/e2e/process-services-cloud/process-filter-results.e2e.ts index b42cf96cec..f900df48ba 100644 --- a/e2e/process-services-cloud/process-filter-results.e2e.ts +++ b/e2e/process-services-cloud/process-filter-results.e2e.ts @@ -78,7 +78,6 @@ describe('Process filters cloud', () => { processDefinitionService = new ProcessDefinitionsService(apiService); simpleAppProcessDefinition = await processDefinitionService.getProcessDefinitionByName('simpleProcess', simpleApp); processInstancesService = new ProcessInstancesService(apiService); - await processInstancesService.createProcessInstance(simpleAppProcessDefinition.entry.key, simpleApp); differentAppUserProcessInstance = await processInstancesService.createProcessInstance(simpleAppProcessDefinition.entry.key, simpleApp, { 'name': StringUtil.generateRandomString(), 'businessKey': StringUtil.generateRandomString() @@ -87,7 +86,6 @@ describe('Process filters cloud', () => { await apiService.login(testUser.email, testUser.password); processDefinition = await processDefinitionService.getProcessDefinitionByName('candidateGroupProcess', candidateBaseApp); anotherProcessDefinition = await processDefinitionService.getProcessDefinitionByName('anotherCandidateGroupProcess', candidateBaseApp); - await processInstancesService.createProcessInstance(processDefinition.entry.key, candidateBaseApp); runningProcessInstance = await processInstancesService.createProcessInstance(processDefinition.entry.key, candidateBaseApp, { 'name': StringUtil.generateRandomString(), @@ -127,6 +125,13 @@ describe('Process filters cloud', () => { }); afterAll(async (done) => { + await processInstancesService.deleteProcessInstance(runningProcessInstance.entry.id, candidateBaseApp); + await processInstancesService.deleteProcessInstance(anotherProcessInstance.entry.id, candidateBaseApp); + await processInstancesService.deleteProcessInstance(suspendProcessInstance.entry.id, candidateBaseApp); + + await apiService.login(anotherUser.email, anotherUser.password); + await processInstancesService.deleteProcessInstance(differentAppUserProcessInstance.entry.id, simpleApp); + await apiService.login(browser.params.identityAdmin.email, browser.params.identityAdmin.password); await identityService.deleteIdentityUser(testUser.idIdentityService); await identityService.deleteIdentityUser(anotherUser.idIdentityService); diff --git a/e2e/process-services/process-instance-details.e2e.ts b/e2e/process-services/process-instance-details.e2e.ts index 6b1be30596..3e6b453d4f 100644 --- a/e2e/process-services/process-instance-details.e2e.ts +++ b/e2e/process-services/process-instance-details.e2e.ts @@ -40,7 +40,7 @@ describe('Process Instance Details', () => { let appModel, process, user; const app = resources.Files.SIMPLE_APP_WITH_USER_FORM; - const PROCESS_DATE_FORMAT = 'mmm dd, yyyy'; + const PROCESS_DATE_FORMAT = 'mmm d, yyyy'; beforeAll(async (done) => { const apps = new AppsActions(); diff --git a/e2e/process-services/task-details.e2e.ts b/e2e/process-services/task-details.e2e.ts index 94cda8723b..a6f43bbb12 100644 --- a/e2e/process-services/task-details.e2e.ts +++ b/e2e/process-services/task-details.e2e.ts @@ -38,7 +38,7 @@ describe('Task Details component', () => { let processUserModel, appModel; const app = resources.Files.SIMPLE_APP_WITH_USER_FORM; const tasks = ['Modifying task', 'Information box', 'No form', 'Not Created', 'Refreshing form', 'Assignee task', 'Attach File']; - const TASK_DATE_FORMAT = 'mmm dd, yyyy'; + const TASK_DATE_FORMAT = 'mmm d, yyyy'; let formModel; let apps; diff --git a/e2e/util/constants.js b/e2e/util/constants.js index 649a3b2e2d..c5182a8f72 100644 --- a/e2e/util/constants.js +++ b/e2e/util/constants.js @@ -118,7 +118,7 @@ exports.PROCESS_BUSINESS_KEY = "None"; exports.PROCESS_DESCRIPTION = "No description"; -exports.PROCESS_DATE_FORMAT = "mmm dd, yyyy"; +exports.PROCESS_DATE_FORMAT = "mmm d, yyyy"; exports.PROCESS_DETAILS = { NO_PARENT: "None", diff --git a/lib/process-services-cloud/src/lib/process/process-filters/components/edit-process-filter-cloud.component.ts b/lib/process-services-cloud/src/lib/process/process-filters/components/edit-process-filter-cloud.component.ts index 60a652d011..d873ecaa80 100644 --- a/lib/process-services-cloud/src/lib/process/process-filters/components/edit-process-filter-cloud.component.ts +++ b/lib/process-services-cloud/src/lib/process/process-filters/components/edit-process-filter-cloud.component.ts @@ -90,7 +90,6 @@ export class EditProcessFilterCloudComponent implements OnInit, OnChanges { status = [ { label: 'ALL', value: '' }, - { label: 'CREATED', value: 'CREATED' }, { label: 'RUNNING', value: 'RUNNING' }, { label: 'SUSPENDED', value: 'SUSPENDED' }, { label: 'CANCELLED', value: 'CANCELLED' }, diff --git a/lib/testing/src/lib/process-services-cloud/actions/process-instances.service.ts b/lib/testing/src/lib/process-services-cloud/actions/process-instances.service.ts index e476bbe7ad..c4a7075450 100644 --- a/lib/testing/src/lib/process-services-cloud/actions/process-instances.service.ts +++ b/lib/testing/src/lib/process-services-cloud/actions/process-instances.service.ts @@ -40,7 +40,7 @@ export class ProcessInstancesService { } catch (error) { // tslint:disable-next-line:no-console - console.log('create process-instances Service not working'); + console.log('create process-instances Service not working', error.message); } } @@ -56,7 +56,7 @@ export class ProcessInstancesService { } catch (error) { // tslint:disable-next-line:no-console - console.log('suspend process-instances Service not working'); + console.log('suspend process-instances Service not working', error.message); } } @@ -71,7 +71,7 @@ export class ProcessInstancesService { } catch (error) { // tslint:disable-next-line:no-console - console.log('delete process-instances Service not working'); + console.log('delete process-instances Service not working', error.message); } } @@ -87,7 +87,7 @@ export class ProcessInstancesService { } catch (error) { // tslint:disable-next-line:no-console - console.log('complete process-instances Service not working'); + console.log('complete process-instances Service not working', error.message); } } } From c9b7722bd00fa81fcf933ea963a58de2123782a4 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Wed, 3 Jul 2019 12:08:12 +0100 Subject: [PATCH 030/140] fix css class name typo (#4895) * fix css class name typo * fix more typos --- .../cloud/community/community-task-details-cloud.component.scss | 2 +- .../app/components/cloud/task-details-cloud-demo.component.scss | 2 +- .../task-header/components/task-header-cloud.component.html | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/demo-shell/src/app/components/cloud/community/community-task-details-cloud.component.scss b/demo-shell/src/app/components/cloud/community/community-task-details-cloud.component.scss index e97ca949e4..e3cc8d8c52 100644 --- a/demo-shell/src/app/components/cloud/community/community-task-details-cloud.component.scss +++ b/demo-shell/src/app/components/cloud/community/community-task-details-cloud.component.scss @@ -5,7 +5,7 @@ display: flex; } - &-task-tiitle { + &-task-title { margin-left:15px; } diff --git a/demo-shell/src/app/components/cloud/task-details-cloud-demo.component.scss b/demo-shell/src/app/components/cloud/task-details-cloud-demo.component.scss index e97ca949e4..e3cc8d8c52 100644 --- a/demo-shell/src/app/components/cloud/task-details-cloud-demo.component.scss +++ b/demo-shell/src/app/components/cloud/task-details-cloud-demo.component.scss @@ -5,7 +5,7 @@ display: flex; } - &-task-tiitle { + &-task-title { margin-left:15px; } diff --git a/lib/process-services-cloud/src/lib/task/task-header/components/task-header-cloud.component.html b/lib/process-services-cloud/src/lib/task/task-header/components/task-header-cloud.component.html index f9fa6a5382..ead649fe3e 100644 --- a/lib/process-services-cloud/src/lib/task/task-header/components/task-header-cloud.component.html +++ b/lib/process-services-cloud/src/lib/task/task-header/components/task-header-cloud.component.html @@ -1,4 +1,4 @@ -

{{ taskDetails.name }}

+

{{ taskDetails.name }}

From 085e1a9dfaa19a58144b6a6a6e1f5c8044709aeb Mon Sep 17 00:00:00 2001 From: Eugenio Romano Date: Wed, 3 Jul 2019 22:42:00 +0100 Subject: [PATCH 031/140] clean unit tests core part 2 (#4897) * promote use setupTestbed * fix context menu unit test * fix sidebar warning unit test * fix spy people widget * fix ISO warning date time widget * fix sidebar spy 404 url * minor karma fix import pdf.js map * restore md * revert extension change --- .../context-menu-holder.component.spec.ts | 1 + .../context-menu-holder.component.ts | 4 +-- .../context-menu-overlay.service.spec.ts | 2 +- .../context-menu/context-menu.service.spec.ts | 32 ------------------- .../widgets/content/content.widget.spec.ts | 12 ++++--- .../date-time/date-time.widget.spec.ts | 8 ++--- .../widgets/people/people.widget.spec.ts | 25 +++++++++++---- lib/core/karma.conf.js | 6 ++++ .../sidebar-action-menu.component.spec.ts | 4 ++- 9 files changed, 44 insertions(+), 50 deletions(-) delete mode 100644 lib/core/context-menu/context-menu.service.spec.ts diff --git a/lib/core/context-menu/context-menu-holder.component.spec.ts b/lib/core/context-menu/context-menu-holder.component.spec.ts index 6206e25794..c7f33b6213 100644 --- a/lib/core/context-menu/context-menu-holder.component.spec.ts +++ b/lib/core/context-menu/context-menu-holder.component.spec.ts @@ -76,6 +76,7 @@ describe('ContextMenuHolderComponent', () => { component = fixture.componentInstance; contextMenuService = TestBed.get(ContextMenuService); + component.ngOnDestroy = () => {}; fixture.detectChanges(); }); diff --git a/lib/core/context-menu/context-menu-holder.component.ts b/lib/core/context-menu/context-menu-holder.component.ts index 1c03dfca74..1a3e20f13b 100644 --- a/lib/core/context-menu/context-menu-holder.component.ts +++ b/lib/core/context-menu/context-menu-holder.component.ts @@ -80,7 +80,7 @@ export class ContextMenuHolderComponent implements OnInit, OnDestroy { this.subscriptions.push( this.contextMenuService.show.subscribe((mouseEvent) => this.showMenu(mouseEvent.event, mouseEvent.obj)), - this.menuTrigger.onMenuOpen.subscribe(() => { + this.menuTrigger.menuOpened.subscribe(() => { const container = this.overlayContainer.getContainerElement(); if (container) { this.contextMenuListenerFn = this.renderer.listen(container, 'contextmenu', (contextmenuEvent: Event) => { @@ -90,7 +90,7 @@ export class ContextMenuHolderComponent implements OnInit, OnDestroy { this.menuElement = this.getContextMenuElement(); }), - this.menuTrigger.onMenuClose.subscribe(() => { + this.menuTrigger.menuClosed.subscribe(() => { this.menuElement = null; if (this.contextMenuListenerFn) { this.contextMenuListenerFn(); diff --git a/lib/core/context-menu/context-menu-overlay.service.spec.ts b/lib/core/context-menu/context-menu-overlay.service.spec.ts index 6f96d4e3f9..fb5a180559 100644 --- a/lib/core/context-menu/context-menu-overlay.service.spec.ts +++ b/lib/core/context-menu/context-menu-overlay.service.spec.ts @@ -53,7 +53,7 @@ describe('ContextMenuService', () => { ); }); - it('should should create a custom overlay', () => { + it('should create a custom overlay', () => { contextMenuOverlayService.open(overlayConfig); expect(document.querySelector('.test-panel')).not.toBe(null); diff --git a/lib/core/context-menu/context-menu.service.spec.ts b/lib/core/context-menu/context-menu.service.spec.ts deleted file mode 100644 index 2e705760a7..0000000000 --- a/lib/core/context-menu/context-menu.service.spec.ts +++ /dev/null @@ -1,32 +0,0 @@ -/*! - * @license - * Copyright 2019 Alfresco Software, Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { ContextMenuService } from './context-menu.service'; - -describe('ContextMenuService', () => { - - let service; - - beforeEach(() => { - service = new ContextMenuService(); - }); - - it('should setup default show subject', () => { - expect(service.show).toBeDefined(); - }); - -}); diff --git a/lib/core/form/components/widgets/content/content.widget.spec.ts b/lib/core/form/components/widgets/content/content.widget.spec.ts index 6703d5d8d1..9504b7b2e5 100644 --- a/lib/core/form/components/widgets/content/content.widget.spec.ts +++ b/lib/core/form/components/widgets/content/content.widget.spec.ts @@ -42,7 +42,7 @@ describe('ContentWidgetComponent', () => { function createFakeImageBlob() { const data = atob('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=='); - return new Blob([data], {type: 'image/png'}); + return new Blob([data], { type: 'image/png' }); } function createFakePdfBlob(): Blob { @@ -60,7 +60,7 @@ describe('ContentWidgetComponent', () => { 'CjAwMDAwMDAwNzkgMDAwMDAgbiAKMDAwMDAwMDE3MyAwMDAwMCBuIAowMDAwMDAwMzAxIDAw' + 'MDAwIG4gCjAwMDAwMDAzODAgMDAwMDAgbiAKdHJhaWxlcgo8PAogIC9TaXplIDYKICAvUm9v' + 'dCAxIDAgUgo+PgpzdGFydHhyZWYKNDkyCiUlRU9G'); - return new Blob([pdfData], {type: 'application/pdf'}); + return new Blob([pdfData], { type: 'application/pdf' }); } setupTestBed({ @@ -165,7 +165,7 @@ describe('ContentWidgetComponent', () => { const contentId = 1; const change = new SimpleChange(null, contentId, true); - component.ngOnChanges({'id': change}); + component.ngOnChanges({ 'id': change }); jasmine.Ajax.requests.mostRecent().respondWith({ status: 200, @@ -193,7 +193,7 @@ describe('ContentWidgetComponent', () => { const contentId = 1; const change = new SimpleChange(null, contentId, true); - component.ngOnChanges({'id': change}); + component.ngOnChanges({ 'id': change }); component.contentLoaded.subscribe((res) => { fixture.detectChanges(); @@ -250,6 +250,8 @@ describe('ContentWidgetComponent', () => { thumbnailStatus: 'created' }); + component.content.thumbnailUrl = '/alfresco-logo.svg'; + component.contentClick.subscribe((content) => { expect(content.contentBlob).toBe(blob); expect(content.mimeType).toBe('application/pdf'); @@ -284,6 +286,8 @@ describe('ContentWidgetComponent', () => { thumbnailStatus: 'created' }); + component.content.thumbnailUrl = '/alfresco-logo.svg'; + fixture.detectChanges(); const downloadButton: any = element.querySelector('#download'); downloadButton.click(); diff --git a/lib/core/form/components/widgets/date-time/date-time.widget.spec.ts b/lib/core/form/components/widgets/date-time/date-time.widget.spec.ts index 18540602b5..a58ab7195c 100644 --- a/lib/core/form/components/widgets/date-time/date-time.widget.spec.ts +++ b/lib/core/form/components/widgets/date-time/date-time.widget.spec.ts @@ -50,7 +50,7 @@ describe('DateTimeWidgetComponent', () => { }); it('should setup min value for date picker', () => { - const minValue = '1982-03-13T10:00Z'; + const minValue = '1982-03-13T10:00:000Z'; widget.field = new FormFieldModel(null, { id: 'date-id', name: 'date-name', @@ -77,7 +77,7 @@ describe('DateTimeWidgetComponent', () => { }); it('should setup max value for date picker', () => { - const maxValue = '1982-03-13T10:00Z'; + const maxValue = '1982-03-13T10:00:000Z'; widget.field = new FormFieldModel(null, { maxValue: maxValue }); @@ -93,14 +93,14 @@ describe('DateTimeWidgetComponent', () => { const field = new FormFieldModel(new FormModel(), { id: 'date-field-id', name: 'date-name', - value: '9-12-9999 10:00 AM', + value: '09-12-9999 10:00 AM', type: 'datetime', readOnly: 'false' }); widget.field = field; - widget.onDateChanged({ value: moment('13-03-1982 10:00 AM') }); + widget.onDateChanged({ value: moment('2008-09-15T15:53:00') }); expect(widget.onFieldChanged).toHaveBeenCalledWith(field); }); diff --git a/lib/core/form/components/widgets/people/people.widget.spec.ts b/lib/core/form/components/widgets/people/people.widget.spec.ts index 44ed1b36a7..1f7d0c6cc9 100644 --- a/lib/core/form/components/widgets/people/people.widget.spec.ts +++ b/lib/core/form/components/widgets/people/people.widget.spec.ts @@ -49,8 +49,12 @@ describe('PeopleWidgetComponent', () => { formService = TestBed.get(FormService); translationService = TestBed.get(TranslateService); - spyOn(translationService, 'instant').and.callFake((key) => { return key; }); - spyOn(translationService, 'get').and.callFake((key) => { return of(key); }); + spyOn(translationService, 'instant').and.callFake((key) => { + return key; + }); + spyOn(translationService, 'get').and.callFake((key) => { + return of(key); + }); element = fixture.nativeElement; widget = fixture.componentInstance; @@ -143,7 +147,14 @@ describe('PeopleWidgetComponent', () => { expect(widget.groupId).toBe(''); }); - it('should display involved user in task form', async() => { + it('should display involved user in task form', async () => { + spyOn(formService, 'getWorkflowUsers').and.returnValue( + new Observable((observer) => { + observer.next(null); + observer.complete(); + }) + ); + widget.field.value = new UserProcessModel({ id: 'people-id', firstName: 'John', @@ -180,8 +191,10 @@ describe('PeopleWidgetComponent', () => { element = fixture.nativeElement; })); - afterEach(() => { - fixture.destroy(); + afterAll(() => { + if (fixture) { + fixture.destroy(); + } TestBed.resetTestingModule(); }); @@ -243,7 +256,7 @@ describe('PeopleWidgetComponent', () => { }); })); - it('should emit peopleSelected if option is valid', async() => { + it('should emit peopleSelected if option is valid', async () => { const selectEmitSpy = spyOn(widget.peopleSelected, 'emit'); const peopleHTMLElement: HTMLInputElement = element.querySelector('input'); peopleHTMLElement.focus(); diff --git a/lib/core/karma.conf.js b/lib/core/karma.conf.js index 47c44d0143..8db34eafad 100644 --- a/lib/core/karma.conf.js +++ b/lib/core/karma.conf.js @@ -8,16 +8,21 @@ module.exports = function (config) { files: [ {pattern: 'node_modules/core-js/client/core.js', included: true, watched: false}, {pattern: 'node_modules/tslib/tslib.js', included: true, watched: false}, + {pattern: 'node_modules/hammerjs/hammer.min.js', included: true, watched: false}, {pattern: 'node_modules/hammerjs/hammer.min.js.map', included: false, watched: false}, // pdf-js {pattern: 'node_modules/pdfjs-dist/build/pdf.js.map', included: false, watched: false}, {pattern: 'node_modules/pdfjs-dist/build/pdf.js', included: true, watched: false}, + {pattern: 'node_modules/pdfjs-dist/build/pdf.worker.js', included: true, watched: false, served: true}, {pattern: 'node_modules/pdfjs-dist/build/pdf.worker.js.map', included: false, watched: false}, {pattern: 'node_modules/pdfjs-dist/build/pdf.worker.min.js', included: true, watched: false, served: true}, + {pattern: 'node_modules/pdfjs-dist/web/pdf_viewer.js', included: true, watched: false}, + {pattern: 'node_modules/pdfjs-dist/web/pdf_viewer.js.map', served: true, included: false, watched: false}, + { pattern: 'node_modules/@angular/material/prebuilt-themes/indigo-pink.css', included: true, @@ -47,6 +52,7 @@ module.exports = function (config) { '/pdf.worker.min.js' :'/base/node_modules/pdfjs-dist/build/pdf.worker.min.js', '/pdf.worker.js' :'/base/node_modules/pdfjs-dist/build/pdf.worker.js', '/fake-url-file.png' :'/base/lib/core/assets/images/logo.png', + '/logo.png' :'/base/lib/core/assets/images/logo.png', '/alfresco-logo.svg' :'/base/lib/core/assets/images/alfresco-logo.svg', '/assets/images/': '/base/lib/core/assets/images/', '/assets/images/ecm-background.png': '/base/lib/core/assets/images/ecm-background.png', diff --git a/lib/core/layout/components/sidebar-action/sidebar-action-menu.component.spec.ts b/lib/core/layout/components/sidebar-action/sidebar-action-menu.component.spec.ts index 4634444800..41eb53d423 100644 --- a/lib/core/layout/components/sidebar-action/sidebar-action-menu.component.spec.ts +++ b/lib/core/layout/components/sidebar-action/sidebar-action-menu.component.spec.ts @@ -21,6 +21,7 @@ import { MaterialModule } from '../../../material.module'; import { SidebarActionMenuComponent } from './sidebar-action-menu.component'; import { setupTestBed } from '../../../testing/setupTestBed'; import { CoreTestingModule } from '../../../testing/core.testing.module'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; describe('SidebarActionMenuComponent', () => { let element: HTMLElement; @@ -91,7 +92,8 @@ describe('Custom SidebarActionMenuComponent', () => { CustomSidebarActionMenuComponent ], imports: [ - MaterialModule + MaterialModule, + NoopAnimationsModule ] }); From a580b6eb1572d9fe44fb305768d4765ce03065b5 Mon Sep 17 00:00:00 2001 From: Marouan Bentaleb <38426175+marouanbentaleb@users.noreply.github.com> Date: Thu, 4 Jul 2019 13:21:51 +0100 Subject: [PATCH 032/140] Changes required to adf-testing (#4898) --- lib/testing/src/lib/core/pages/login-sso.page.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/testing/src/lib/core/pages/login-sso.page.ts b/lib/testing/src/lib/core/pages/login-sso.page.ts index 4238e14018..31212a6b9b 100644 --- a/lib/testing/src/lib/core/pages/login-sso.page.ts +++ b/lib/testing/src/lib/core/pages/login-sso.page.ts @@ -24,7 +24,7 @@ export class LoginSSOPage { ssoButton = element(by.css(`[data-automation-id="login-button-sso"]`)); usernameField = element(by.id('username')); passwordField = element(by.id('password')); - loginButton = element(by.css('input[class="submit"]')); + loginButton = element(by.css('input[type="submit"]')); header = element(by.id('adf-header')); loginError = element(by.css(`div[data-automation-id="login-error"]`)); From 5ed570b36f363162c38bea6af8861dc24665c4d8 Mon Sep 17 00:00:00 2001 From: Marouan Bentaleb <38426175+marouanbentaleb@users.noreply.github.com> Date: Fri, 5 Jul 2019 11:46:46 +0100 Subject: [PATCH 033/140] Changes required to adf-testing (#4901) --- lib/testing/src/lib/core/pages/login.page.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/testing/src/lib/core/pages/login.page.ts b/lib/testing/src/lib/core/pages/login.page.ts index 85f36ebcb3..f701a19b84 100644 --- a/lib/testing/src/lib/core/pages/login.page.ts +++ b/lib/testing/src/lib/core/pages/login.page.ts @@ -195,7 +195,7 @@ export class LoginPage { } clickSignInButton() { - BrowserActions.clickExecuteScript('#login-button'); + BrowserActions.click(this.signInButton); } clickSettingsIcon() { From 10673ef6f63e542f40c8281186f74deab4419229 Mon Sep 17 00:00:00 2001 From: Geeta Mandakini Ayyalasomayajula <45559635+gmandakini@users.noreply.github.com> Date: Fri, 5 Jul 2019 11:47:35 +0100 Subject: [PATCH 034/140] [C297472] Should be able to see selected tasks (#4899) * update * automated => C297472 see selected rows list and task names when multiselect and testing mode toggle are on. * automated => C297472 see selected rows list and task names when multiselect and testing mode toggle are on. * Delete package-lock.json * updates --- .../process-services/tasksCloudDemoPage.ts | 24 +++++++++++++++++++ .../task-list-selection.e2e.ts | 16 +++++++++++++ 2 files changed, 40 insertions(+) diff --git a/e2e/pages/adf/demo-shell/process-services/tasksCloudDemoPage.ts b/e2e/pages/adf/demo-shell/process-services/tasksCloudDemoPage.ts index 65019cf0cc..8d7ff342af 100644 --- a/e2e/pages/adf/demo-shell/process-services/tasksCloudDemoPage.ts +++ b/e2e/pages/adf/demo-shell/process-services/tasksCloudDemoPage.ts @@ -42,6 +42,9 @@ export class TasksCloudDemoPage { displayTaskDetailsToggle = element(by.css('mat-slide-toggle[data-automation-id="taskDetailsRedirection"]')); displayProcessDetailsToggle = element(by.css('mat-slide-toggle[data-automation-id="processDetailsRedirection"]')); multiSelectionToggle = element(by.css('mat-slide-toggle[data-automation-id="multiSelection"]')); + testingModeToggle = element(by.css('mat-slide-toggle[data-automation-id="testingMode"]')); + selectedRows = element(by.xpath("//div[text()=' Selected rows: ']")); + noOfSelectedRows = element.all(by.xpath("//div[text()=' Selected rows: ']//li")); formControllersPage = new FormControllersPage(); @@ -62,6 +65,11 @@ export class TasksCloudDemoPage { return this; } + enableTestingMode() { + this.formControllersPage.enableToggle(this.testingModeToggle); + return this; + } + taskFiltersCloudComponent(filter) { return new TaskFiltersCloudComponentPage(filter); } @@ -131,4 +139,20 @@ export class TasksCloudDemoPage { BrowserActions.click(this.modeDropDownArrow); BrowserVisibility.waitUntilElementIsVisible(this.modeSelector); } + + checkSelectedRowsIsDisplayed() { + BrowserVisibility.waitUntilElementIsVisible(this.selectedRows); + return this; + } + + getNoOfSelectedRows() { + this.checkSelectedRowsIsDisplayed(); + return this.noOfSelectedRows.count(); + } + + getSelectedTaskRowText(rowNo: string) { + this.checkSelectedRowsIsDisplayed(); + const row = element(by.xpath(`//div[text()=' Selected rows: ']//li[${rowNo}]`)); + return row.getText(); + } } diff --git a/e2e/process-services-cloud/task-list-selection.e2e.ts b/e2e/process-services-cloud/task-list-selection.e2e.ts index 39d9a1a8c7..50f59d6d64 100644 --- a/e2e/process-services-cloud/task-list-selection.e2e.ts +++ b/e2e/process-services-cloud/task-list-selection.e2e.ts @@ -167,6 +167,22 @@ describe('Task list cloud - selection', () => { tasksCloudDemoPage.taskListCloudComponent().checkRowIsChecked(tasks[2]); }); + it('[C297472] Should be able to see selected tasks with Multiselection and Testing switched on', () => { + tasksCloudDemoPage.clickSettingsButton().enableMultiSelection(); + tasksCloudDemoPage.clickSettingsButton().enableTestingMode(); + tasksCloudDemoPage.clickAppButton(); + tasksCloudDemoPage.taskListCloudComponent().getDataTable().waitForTableBody(); + + tasksCloudDemoPage.taskListCloudComponent().checkContentIsDisplayedByName(tasks[0]); + tasksCloudDemoPage.taskListCloudComponent().clickCheckbox(tasks[0]); + tasksCloudDemoPage.taskListCloudComponent().checkContentIsDisplayedByName(tasks[1]); + tasksCloudDemoPage.taskListCloudComponent().clickCheckbox(tasks[1]); + + expect(tasksCloudDemoPage.getNoOfSelectedRows()).toBe(2); + expect(tasksCloudDemoPage.getSelectedTaskRowText('1')).toBe(tasks[0]); + expect(tasksCloudDemoPage.getSelectedTaskRowText('2')).toBe(tasks[1]); + }); + }); }); From b88888b5e41a459a8d40583b91091d1e3e323270 Mon Sep 17 00:00:00 2001 From: siva kumar Date: Fri, 5 Jul 2019 16:22:36 +0530 Subject: [PATCH 035/140] [ADF-4614] User preferences in process filters (#4889) * * Created UserPreferenceCloudService. * * Refactored processfiltercloud service. * Refactored user-preferncecloud service. * Added unit tests to the services. * * Updated unit tests * FIxed Synx problem. * * Fixed edit-filter error. * * Fixed failing edit-process-filter unit test. * * Added comments in processfilter/prefernces services. * * Fixed memory leak* Added a spinner in the edit-process-filter component * * Fixed comments. * * Removed unnecessary filter property --- .../cloud/cloud-filters-demo.component.ts | 2 +- .../src/lib/mock/user-preference.mock.ts | 95 ++++++ .../src/lib/process-services-cloud.module.ts | 4 +- .../edit-process-filter-cloud.component.html | 119 +++---- .../edit-process-filter-cloud.component.scss | 8 + ...dit-process-filter-cloud.component.spec.ts | 48 ++- .../edit-process-filter-cloud.component.ts | 65 ++-- .../process-filters-cloud.component.spec.ts | 3 +- .../process-filters-cloud.component.ts | 17 +- .../mock/process-filters.cloud.mock.ts | 191 +++++++++++ .../process-filter-cloud.service.spec.ts | 210 +++++++++++++ .../services/process-filter-cloud.service.ts | 296 ++++++++++++------ .../src/lib/services/public-api.ts | 1 + .../user-preference.cloud.service.spec.ts | 201 ++++++++++++ .../services/user-preference.cloud.service.ts | 150 +++++++++ 15 files changed, 1219 insertions(+), 191 deletions(-) create mode 100644 lib/process-services-cloud/src/lib/mock/user-preference.mock.ts create mode 100644 lib/process-services-cloud/src/lib/process/process-filters/mock/process-filters.cloud.mock.ts create mode 100644 lib/process-services-cloud/src/lib/process/process-filters/services/process-filter-cloud.service.spec.ts create mode 100644 lib/process-services-cloud/src/lib/services/user-preference.cloud.service.spec.ts create mode 100644 lib/process-services-cloud/src/lib/services/user-preference.cloud.service.ts diff --git a/demo-shell/src/app/components/cloud/cloud-filters-demo.component.ts b/demo-shell/src/app/components/cloud/cloud-filters-demo.component.ts index 7f27a2aa3a..2801f72d28 100644 --- a/demo-shell/src/app/components/cloud/cloud-filters-demo.component.ts +++ b/demo-shell/src/app/components/cloud/cloud-filters-demo.component.ts @@ -68,7 +68,7 @@ export class CloudFiltersDemoComponent implements OnInit { } onProcessFilterSelected(filter) { - this.cloudLayoutService.setCurrentProcessFilterParam({id: filter.id}); + this.cloudLayoutService.setCurrentProcessFilterParam({id: filter && filter.id ? filter.id : ''}); const currentFilter = Object.assign({}, filter); this.router.navigate([`/cloud/${this.appName}/processes/`], { queryParams: currentFilter }); } diff --git a/lib/process-services-cloud/src/lib/mock/user-preference.mock.ts b/lib/process-services-cloud/src/lib/mock/user-preference.mock.ts new file mode 100644 index 0000000000..45aff12608 --- /dev/null +++ b/lib/process-services-cloud/src/lib/mock/user-preference.mock.ts @@ -0,0 +1,95 @@ +/*! + * @license + * Copyright 2019 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export const mockPreferences = { + list: { + entries: [ + { + entry: { + key: 'mock-preference-key-1', + value: [ + { username: 'mock-username-1', firstName: 'mock-firstname-1' }, + { username: 'mock-username-2', firstName: 'mock-firstname-2' } + ] + } + }, + { + entry: { + key: 'mock-preference-key-2', + value: 'my mock preference value' + } + }, + { + entry: { + key: 'mock-preference-key-3', + value: { + name: 'my-filter', + id: '3', + key: 'my-filter', + icon: 'adjust', + appName: 'mock-appName', + sort: 'startDate', + state: 'MOCK-COMPLETED', + order: 'DESC' + } + } + } + ], + pagination: { + skipCount: 0, + maxItems: 100, + count: 3, + hasMoreItems: false, + totalItems: 3 + } + } +}; + +export const fakeEmptyPreferences = { + list: { + entries: [], + pagination: { + skipCount: 0, + maxItems: 100, + count: 0, + hasMoreItems: false, + totalItems: 0 + } + } +}; + +export const createMockPreference = { + name: 'create-preference', + id: '1', + key: 'my-preference', + icon: 'adjust', + appName: 'mock-appName' +}; + +export const updateMockPreference = { + name: 'update-preference', + id: '1', + key: 'update-preference', + icon: 'adjust', + appName: 'mock-appName' +}; + +export const getMockPreference = + [ + { username: 'mock-username-1', firstName: 'mock-firstname-1', appName: 'mock-appName' }, + { username: 'mock-username-2', firstName: 'mock-firstname-2', appName: 'mock-appName' } + ]; diff --git a/lib/process-services-cloud/src/lib/process-services-cloud.module.ts b/lib/process-services-cloud/src/lib/process-services-cloud.module.ts index 01aa3ed579..c16fb19b41 100644 --- a/lib/process-services-cloud/src/lib/process-services-cloud.module.ts +++ b/lib/process-services-cloud/src/lib/process-services-cloud.module.ts @@ -24,6 +24,7 @@ import { GroupCloudModule } from './group/group-cloud.module'; import { FormCloudModule } from './form/form-cloud.module'; import { TaskFormModule } from './task/task-form/task-form.module'; import { BaseCloudService } from './services/base-cloud.service'; +import { UserPreferenceCloudService } from './services/user-preference.cloud.service'; @NgModule({ imports: [ @@ -44,7 +45,8 @@ import { BaseCloudService } from './services/base-cloud.service'; source: 'assets/adf-process-services-cloud' } }, - BaseCloudService + BaseCloudService, + UserPreferenceCloudService ], exports: [ AppListCloudModule, diff --git a/lib/process-services-cloud/src/lib/process/process-filters/components/edit-process-filter-cloud.component.html b/lib/process-services-cloud/src/lib/process/process-filters/components/edit-process-filter-cloud.component.html index f506e6ccb6..e921429b53 100644 --- a/lib/process-services-cloud/src/lib/process/process-filters/components/edit-process-filter-cloud.component.html +++ b/lib/process-services-cloud/src/lib/process/process-filters/components/edit-process-filter-cloud.component.html @@ -1,60 +1,69 @@ - + - - {{processFilter.name | translate}} - - {{ 'ADF_CLOUD_EDIT_PROCESS_FILTER.TITLE' | translate}} -
- - + + + {{processFilter.name | translate}} + + {{ 'ADF_CLOUD_EDIT_PROCESS_FILTER.TITLE' | translate}} +
+ + + +
+
+
+ +
+ +
+
+
+ +
+
+ + + + + {{ propertyOption.label }} + + + + + + + + {{processFilterProperty.label | translate}} + + + +
+
+
{{'ADF_CLOUD_EDIT_PROCESS_FILTER.ERROR.DATE' | translate}}
+ warning +
+
+
- - - -
- - - - - {{ propertyOption.label }} - - - - - - - - {{processFilterProperty.label | translate}} - - - -
-
-
{{'ADF_CLOUD_EDIT_PROCESS_FILTER.ERROR.DATE' | translate}}
- warning -
-
-
-
-
-
+ +
diff --git a/lib/process-services-cloud/src/lib/process/process-filters/components/edit-process-filter-cloud.component.scss b/lib/process-services-cloud/src/lib/process/process-filters/components/edit-process-filter-cloud.component.scss index 498ba1f835..63a7de9a7e 100644 --- a/lib/process-services-cloud/src/lib/process/process-filters/components/edit-process-filter-cloud.component.scss +++ b/lib/process-services-cloud/src/lib/process/process-filters/components/edit-process-filter-cloud.component.scss @@ -28,4 +28,12 @@ color: mat-color($warn); } } + + .adf { + + &-cloud-edit-process-filter-loading-margin { + margin-left: calc((100% - 100px) / 2); + margin-right: calc((100% - 100px) / 2); + } + } } diff --git a/lib/process-services-cloud/src/lib/process/process-filters/components/edit-process-filter-cloud.component.spec.ts b/lib/process-services-cloud/src/lib/process/process-filters/components/edit-process-filter-cloud.component.spec.ts index 696dd114cb..1ac66263bf 100644 --- a/lib/process-services-cloud/src/lib/process/process-filters/components/edit-process-filter-cloud.component.spec.ts +++ b/lib/process-services-cloud/src/lib/process/process-filters/components/edit-process-filter-cloud.component.spec.ts @@ -32,6 +32,7 @@ import { AppsProcessCloudService } from '../../../app/services/apps-process-clou import { fakeApplicationInstance } from './../../../app/mock/app-model.mock'; import moment from 'moment-es6'; import { AbstractControl } from '@angular/forms'; +import { UserPreferenceCloudService } from '../../../services/user-preference.cloud.service'; describe('EditProcessFilterCloudComponent', () => { let component: EditProcessFilterCloudComponent; @@ -55,7 +56,7 @@ describe('EditProcessFilterCloudComponent', () => { setupTestBed({ imports: [ProcessServiceCloudTestingModule, ProcessFiltersCloudModule], - providers: [MatDialog] + providers: [MatDialog, UserPreferenceCloudService] }); beforeEach(() => { @@ -73,7 +74,7 @@ describe('EditProcessFilterCloudComponent', () => { }); } }); - getProcessFilterByIdSpy = spyOn(service, 'getProcessFilterById').and.returnValue(fakeFilter); + getProcessFilterByIdSpy = spyOn(service, 'getFilterById').and.returnValue(of(fakeFilter)); getRunningApplicationsSpy = spyOn(appsService, 'getDeployedApplicationsByStatus').and.returnValue(of(fakeApplicationInstance)); fixture.detectChanges(); }); @@ -101,7 +102,7 @@ describe('EditProcessFilterCloudComponent', () => { }); })); - it('should display filter name as title', () => { + it('should display filter name as title', async(() => { const processFilterIDchange = new SimpleChange(null, 'mock-process-filter-id', true); component.ngOnChanges({ 'id': processFilterIDchange }); fixture.detectChanges(); @@ -114,7 +115,37 @@ describe('EditProcessFilterCloudComponent', () => { expect(title.innerText).toEqual('FakeRunningProcess'); expect(subTitle.innerText.trim()).toEqual('ADF_CLOUD_EDIT_PROCESS_FILTER.TITLE'); }); - }); + })); + + it('should not display mat-spinner if isloading set to false', async(() => { + const processFilterIDchange = new SimpleChange(null, 'mock-process-filter-id', true); + component.ngOnChanges({ 'id': processFilterIDchange }); + fixture.detectChanges(); + const title = fixture.debugElement.nativeElement.querySelector('#adf-edit-process-filter-title-id'); + const subTitle = fixture.debugElement.nativeElement.querySelector('#adf-edit-process-filter-sub-title-id'); + const matSpinnerElement = fixture.debugElement.nativeElement.querySelector('.adf-cloud-edit-process-filter-loading-margin'); + + fixture.whenStable().then(() => { + expect(matSpinnerElement).toBeNull(); + expect(title).toBeDefined(); + expect(subTitle).toBeDefined(); + expect(title.innerText).toEqual('FakeRunningProcess'); + expect(subTitle.innerText.trim()).toEqual('ADF_CLOUD_EDIT_PROCESS_FILTER.TITLE'); + }); + })); + + it('should display mat-spinner if isloading set to true', async(() => { + component.isLoading = true; + const processFilterIDchange = new SimpleChange(null, 'mock-process-filter-id', true); + component.ngOnChanges({ 'id': processFilterIDchange }); + fixture.detectChanges(); + + const matSpinnerElement = fixture.debugElement.nativeElement.querySelector('.adf-cloud-edit-process-filter-loading-margin'); + + fixture.whenStable().then(() => { + expect(matSpinnerElement).toBeDefined(); + }); + })); describe('EditProcessFilter form', () => { @@ -333,13 +364,13 @@ describe('EditProcessFilterCloudComponent', () => { })); it('should display sort properties when sort properties are specified', async(() => { - getProcessFilterByIdSpy.and.returnValue({ + getProcessFilterByIdSpy.and.returnValue(of({ id: 'filter-id', processName: 'process-name', sort: 'my-custom-sort', processDefinitionId: 'process-definition-id', priority: '12' - }); + })); component.sortProperties = ['id', 'processName', 'processDefinitionId']; fixture.detectChanges(); const processFilterIdchange = new SimpleChange(null, 'mock-process-filter-id', true); @@ -367,12 +398,13 @@ describe('EditProcessFilterCloudComponent', () => { beforeEach(() => { const processFilterIDchange = new SimpleChange(null, 'mock-process-filter-id', true); component.ngOnChanges({ 'id': processFilterIDchange }); + getProcessFilterByIdSpy.and.returnValue(of(fakeFilter)); fixture.detectChanges(); }); it('should emit save event and save the filter on click save button', async(() => { component.toggleFilterActions = true; - const saveFilterSpy = spyOn(service, 'updateFilter').and.returnValue(fakeFilter); + const saveFilterSpy = spyOn(service, 'updateFilter').and.returnValue(of(fakeFilter)); const saveSpy: jasmine.Spy = spyOn(component.action, 'emit'); fixture.detectChanges(); @@ -395,7 +427,7 @@ describe('EditProcessFilterCloudComponent', () => { it('should emit delete event and delete the filter on click of delete button', async(() => { component.toggleFilterActions = true; - const deleteFilterSpy = spyOn(service, 'deleteFilter').and.callThrough(); + const deleteFilterSpy = spyOn(service, 'deleteFilter').and.returnValue(of()); const deleteSpy: jasmine.Spy = spyOn(component.action, 'emit'); fixture.detectChanges(); diff --git a/lib/process-services-cloud/src/lib/process/process-filters/components/edit-process-filter-cloud.component.ts b/lib/process-services-cloud/src/lib/process/process-filters/components/edit-process-filter-cloud.component.ts index d873ecaa80..6835c3b6f3 100644 --- a/lib/process-services-cloud/src/lib/process/process-filters/components/edit-process-filter-cloud.component.ts +++ b/lib/process-services-cloud/src/lib/process/process-filters/components/edit-process-filter-cloud.component.ts @@ -15,10 +15,11 @@ * limitations under the License. */ -import { Component, Input, Output, EventEmitter, OnInit, OnChanges, SimpleChanges } from '@angular/core'; +import { Component, Input, Output, EventEmitter, OnInit, OnChanges, SimpleChanges, OnDestroy } from '@angular/core'; import { FormGroup, FormBuilder, AbstractControl } from '@angular/forms'; import { MatDialog, DateAdapter } from '@angular/material'; -import { debounceTime, filter } from 'rxjs/operators'; +import { debounceTime, filter, takeUntil } from 'rxjs/operators'; +import { Subject } from 'rxjs'; import moment from 'moment-es6'; import { Moment } from 'moment'; @@ -34,7 +35,7 @@ import { ProcessFilterDialogCloudComponent } from './process-filter-dialog-cloud templateUrl: './edit-process-filter-cloud.component.html', styleUrls: ['./edit-process-filter-cloud.component.scss'] }) -export class EditProcessFilterCloudComponent implements OnInit, OnChanges { +export class EditProcessFilterCloudComponent implements OnInit, OnChanges, OnDestroy { public static ACTION_SAVE = 'save'; public static ACTION_SAVE_AS = 'saveAs'; @@ -106,6 +107,9 @@ export class EditProcessFilterCloudComponent implements OnInit, OnChanges { processFilterActions: ProcessFilterAction[] = []; toggleFilterActions: boolean = false; + private onDestroy$ = new Subject(); + isLoading: boolean = false; + constructor( private formBuilder: FormBuilder, public dialog: MatDialog, @@ -124,9 +128,7 @@ export class EditProcessFilterCloudComponent implements OnInit, OnChanges { ngOnChanges(changes: SimpleChanges) { const id = changes['id']; if (id && id.currentValue !== id.previousValue) { - this.processFilterProperties = this.createAndFilterProperties(); - this.processFilterActions = this.createAndFilterActions(); - this.buildForm(this.processFilterProperties); + this.retrieveProcessFilterAndBuildForm(); } } @@ -147,10 +149,20 @@ export class EditProcessFilterCloudComponent implements OnInit, OnChanges { } /** - * Return process instance filter by application name and filter id + * Fetches process instance filter by application name and filter id and creates filter properties, build form */ - retrieveProcessFilter(): ProcessFilterCloudModel { - return new ProcessFilterCloudModel(this.processFilterCloudService.getProcessFilterById(this.appName, this.id)); + retrieveProcessFilterAndBuildForm() { + this.isLoading = true; + this.processFilterCloudService.getFilterById(this.appName, this.id) + .pipe(takeUntil(this.onDestroy$)).subscribe((response) => { + this.isLoading = false; + this.processFilter = new ProcessFilterCloudModel(response); + this.processFilterProperties = this.createAndFilterProperties(); + this.processFilterActions = this.createAndFilterActions(); + this.buildForm(this.processFilterProperties); + }, (error) => { + this.isLoading = false; + }); } /** @@ -173,7 +185,6 @@ export class EditProcessFilterCloudComponent implements OnInit, OnChanges { this.applicationNames = []; this.getRunningApplications(); } - this.processFilter = this.retrieveProcessFilter(); const defaultProperties = this.createProcessFilterProperties(this.processFilter); let filteredProperties = defaultProperties.filter((filterProperty: ProcessFilterProperties) => this.isValidProperty(this.filterProperties, filterProperty)); if (!this.hasSortProperty()) { @@ -182,7 +193,6 @@ export class EditProcessFilterCloudComponent implements OnInit, OnChanges { if (this.hasLastModifiedProperty()) { filteredProperties = [...filteredProperties, ...this.createLastModifiedProperty()]; } - return filteredProperties; } @@ -283,7 +293,7 @@ export class EditProcessFilterCloudComponent implements OnInit, OnChanges { getRunningApplications() { this.appsProcessCloudService.getDeployedApplicationsByStatus(EditProcessFilterCloudComponent.APP_RUNNING_STATUS) - .subscribe((applications: ApplicationInstanceModel[]) => { + .pipe(takeUntil(this.onDestroy$)).subscribe((applications: ApplicationInstanceModel[]) => { if (applications && applications.length > 0) { applications.map((application) => { this.applicationNames.push({ label: application.name, value: application.name }); @@ -306,19 +316,23 @@ export class EditProcessFilterCloudComponent implements OnInit, OnChanges { * Save a process instance filter */ save(saveAction: ProcessFilterAction) { - this.processFilterCloudService.updateFilter(this.changedProcessFilter); - saveAction.filter = this.changedProcessFilter; - this.action.emit(saveAction); - this.formHasBeenChanged = this.compareFilters(this.changedProcessFilter, this.processFilter); + this.processFilterCloudService.updateFilter(this.changedProcessFilter) + .pipe(takeUntil(this.onDestroy$)).subscribe((res) => { + saveAction.filter = this.changedProcessFilter; + this.action.emit(saveAction); + this.formHasBeenChanged = this.compareFilters(this.changedProcessFilter, this.processFilter); + }); } /** * Delete a process instance filter */ delete(deleteAction: ProcessFilterAction) { - this.processFilterCloudService.deleteFilter(this.processFilter); - deleteAction.filter = this.processFilter; - this.action.emit(deleteAction); + this.processFilterCloudService.deleteFilter(this.processFilter) + .pipe(takeUntil(this.onDestroy$)).subscribe((res) => { + deleteAction.filter = this.processFilter; + this.action.emit(deleteAction); + }); } /** @@ -343,9 +357,11 @@ export class EditProcessFilterCloudComponent implements OnInit, OnChanges { key: 'custom-' + filterKey }; const resultFilter: ProcessFilterCloudModel = Object.assign({}, this.changedProcessFilter, newFilter); - this.processFilterCloudService.addFilter(resultFilter); - saveAsAction.filter = resultFilter; - this.action.emit(saveAsAction); + this.processFilterCloudService.addFilter(resultFilter) + .pipe(takeUntil(this.onDestroy$)).subscribe((res) => { + saveAsAction.filter = resultFilter; + this.action.emit(saveAsAction); + }); } }); } @@ -515,4 +531,9 @@ export class EditProcessFilterCloudComponent implements OnInit, OnChanges { }) ]; } + + ngOnDestroy() { + this.onDestroy$.next(true); + this.onDestroy$.complete(); + } } diff --git a/lib/process-services-cloud/src/lib/process/process-filters/components/process-filters-cloud.component.spec.ts b/lib/process-services-cloud/src/lib/process/process-filters/components/process-filters-cloud.component.spec.ts index 249f2dff48..161f3e0f53 100644 --- a/lib/process-services-cloud/src/lib/process/process-filters/components/process-filters-cloud.component.spec.ts +++ b/lib/process-services-cloud/src/lib/process/process-filters/components/process-filters-cloud.component.spec.ts @@ -26,6 +26,7 @@ import { By } from '@angular/platform-browser'; import { ProcessServiceCloudTestingModule } from '../../../testing/process-service-cloud.testing.module'; import { ProcessFiltersCloudModule } from '../process-filters-cloud.module'; import { FilterParamsModel } from '../../../task/task-filters/models/filter-cloud.model'; +import { UserPreferenceCloudService } from '../../../services/user-preference.cloud.service'; describe('ProcessFiltersCloudComponent', () => { @@ -75,7 +76,7 @@ describe('ProcessFiltersCloudComponent', () => { setupTestBed({ imports: [ProcessServiceCloudTestingModule, ProcessFiltersCloudModule], - providers: [ProcessFilterCloudService] + providers: [ProcessFilterCloudService, UserPreferenceCloudService] }); beforeEach(() => { diff --git a/lib/process-services-cloud/src/lib/process/process-filters/components/process-filters-cloud.component.ts b/lib/process-services-cloud/src/lib/process/process-filters/components/process-filters-cloud.component.ts index 879cfd597b..7b0a50a134 100644 --- a/lib/process-services-cloud/src/lib/process/process-filters/components/process-filters-cloud.component.ts +++ b/lib/process-services-cloud/src/lib/process/process-filters/components/process-filters-cloud.component.ts @@ -15,18 +15,20 @@ * limitations under the License. */ -import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core'; -import { Observable } from 'rxjs'; +import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges, OnDestroy } from '@angular/core'; +import { Observable, Subject } from 'rxjs'; import { ProcessFilterCloudService } from '../services/process-filter-cloud.service'; import { ProcessFilterCloudModel } from '../models/process-filter-cloud.model'; import { TranslationService } from '@alfresco/adf-core'; import { FilterParamsModel } from '../../../task/task-filters/models/filter-cloud.model'; +import { takeUntil } from 'rxjs/operators'; + @Component({ selector: 'adf-cloud-process-filters', templateUrl: './process-filters-cloud.component.html', styleUrls: ['process-filters-cloud.component.scss'] }) -export class ProcessFiltersCloudComponent implements OnChanges { +export class ProcessFiltersCloudComponent implements OnChanges, OnDestroy { /** (required) The application name */ @Input() @@ -58,6 +60,8 @@ export class ProcessFiltersCloudComponent implements OnChanges { filters: ProcessFilterCloudModel [] = []; + private onDestroy$ = new Subject(); + constructor( private processFilterCloudService: ProcessFilterCloudService, private translationService: TranslationService ) { } @@ -78,7 +82,7 @@ export class ProcessFiltersCloudComponent implements OnChanges { getFilters(appName: string) { this.filters$ = this.processFilterCloudService.getProcessFilters(appName); - this.filters$.subscribe( + this.filters$.pipe(takeUntil(this.onDestroy$)).subscribe( (res: ProcessFilterCloudModel[]) => { this.resetFilter(); this.filters = Object.assign([], res); @@ -163,4 +167,9 @@ export class ProcessFiltersCloudComponent implements OnChanges { this.filters = []; this.currentFilter = undefined; } + + ngOnDestroy() { + this.onDestroy$.next(true); + this.onDestroy$.complete(); + } } diff --git a/lib/process-services-cloud/src/lib/process/process-filters/mock/process-filters.cloud.mock.ts b/lib/process-services-cloud/src/lib/process/process-filters/mock/process-filters.cloud.mock.ts new file mode 100644 index 0000000000..84278df9b8 --- /dev/null +++ b/lib/process-services-cloud/src/lib/process/process-filters/mock/process-filters.cloud.mock.ts @@ -0,0 +1,191 @@ +/*! + * @license + * Copyright 2019 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ProcessFilterCloudModel } from '../models/process-filter-cloud.model'; + +export const fakeProcessCloudFilterEntries = { + list: { + entries: [ + { + entry: { + key: 'process-filters-mock-appName-mock-username', + value: JSON.stringify([ + { + name: 'MOCK_PROCESS_NAME_1', + id: '1', + key: 'all-mock-process', + icon: 'adjust', + appName: 'mock-appName', + sort: 'startDate', + status: 'MOCK_ALL', + order: 'DESC' + }, + { + name: 'MOCK_PROCESS_NAME_2', + id: '2', + key: 'run-mock-process', + icon: 'adjust', + appName: 'mock-appName', + sort: 'startDate', + status: 'MOCK-RUNNING', + order: 'DESC' + }, + { + name: 'MOCK_PROCESS_NAME_3', + id: '3', + key: 'complete-mock-process', + icon: 'adjust', + appName: 'mock-appName', + sort: 'startDate', + status: 'MOCK-COMPLETED', + order: 'DESC' + } + ]) + } + }, + { + entry: { + key: 'mock-key-2', + value: { + name: 'MOCK_PROCESS_NAME_2', + id: '2', + key: 'run-mock-process', + icon: 'adjust', + appName: 'mock-appName', + sort: 'startDate', + status: 'MOCK-RUNNING', + order: 'DESC' + } + } + }, + { + entry: { + key: 'mock-key-3', + value: { + name: 'MOCK_PROCESS_NAME_3', + id: '3', + key: 'complete-mock-process', + icon: 'adjust', + appName: 'mock-appName', + sort: 'startDate', + status: 'MOCK-COMPLETED', + order: 'DESC' + } + } + } + ], + pagination: { + skipCount: 0, + maxItems: 100, + count: 3, + hasMoreItems: false, + totalItems: 3 + } + } +}; + +export const fakeEmptyProcessCloudFilterEntries = { + list: { + entries: [], + pagination: { + skipCount: 0, + maxItems: 100, + count: 0, + hasMoreItems: false, + totalItems: 0 + } + } +}; + +export const fakeProcessCloudFilterWithDifferentEntries = { + list: { + entries: [ + { + entry: { + key: 'my-mock-key-1', + value: 'my-mock-value-2' + } + }, + { + entry: { + key: 'my-mock-key-2', + value: 'my-mock-key-2' + } + } + ], + pagination: { + skipCount: 0, + maxItems: 100, + count: 4, + hasMoreItems: false, + totalItems: 2 + } + } +}; + +export const fakeProcessFilter: ProcessFilterCloudModel = { + name: 'MOCK_PROCESS_NAME_1', + id: '1', + key: 'all-mock-process', + icon: 'adjust', + appName: 'mock-appName', + sort: 'startDate', + status: 'MOCK_ALL', + order: 'DESC', + index: 2, + processName: 'process-name', + processInstanceId: 'processinstanceid', + initiator: 'mockuser', + processDefinitionId: 'processDefid', + processDefinitionKey: 'processDefKey', + lastModified: null, + lastModifiedTo: null, + lastModifiedFrom: null +}; + +export const fakeProcessCloudFilters = [ + { + name: 'MOCK_PROCESS_NAME_1', + id: '1', + key: 'all-mock-process', + icon: 'adjust', + appName: 'mock-appName', + sort: 'startDate', + status: 'MOCK_ALL', + order: 'DESC' + }, + { + name: 'MOCK_PROCESS_NAME_2', + id: '2', + key: 'run-mock-process', + icon: 'adjust', + appName: 'mock-appName', + sort: 'startDate', + status: 'MOCK-RUNNING', + order: 'DESC' + }, + { + name: 'MOCK_PROCESS_NAME_3', + id: '3', + key: 'complete-mock-process', + icon: 'adjust', + appName: 'mock-appName', + sort: 'startDate', + status: 'MOCK-COMPLETED', + order: 'DESC' + } +]; diff --git a/lib/process-services-cloud/src/lib/process/process-filters/services/process-filter-cloud.service.spec.ts b/lib/process-services-cloud/src/lib/process/process-filters/services/process-filter-cloud.service.spec.ts new file mode 100644 index 0000000000..10926dab12 --- /dev/null +++ b/lib/process-services-cloud/src/lib/process/process-filters/services/process-filter-cloud.service.spec.ts @@ -0,0 +1,210 @@ +/*! + * @license + * Copyright 2019 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { async, TestBed } from '@angular/core/testing'; +import { setupTestBed, CoreModule, IdentityUserService } from '@alfresco/adf-core'; +import { of } from 'rxjs'; +import { ProcessFilterCloudService } from './process-filter-cloud.service'; +import { UserPreferenceCloudService } from '../../../services/user-preference.cloud.service'; +import { + fakeProcessCloudFilterEntries, + fakeProcessCloudFilters, + fakeEmptyProcessCloudFilterEntries, + fakeProcessCloudFilterWithDifferentEntries, + fakeProcessFilter +} from '../mock/process-filters.cloud.mock'; + +describe('Process Filter Cloud Service', () => { + let service: ProcessFilterCloudService; + let userPreferenceCloudService: UserPreferenceCloudService; + let identityUserService: IdentityUserService; + let getPreferencesSpy: jasmine.Spy; + let getPreferenceByKeySpy: jasmine.Spy; + let updatePreferenceSpy: jasmine.Spy; + let createPreferenceSpy: jasmine.Spy; + let getCurrentUserInfoSpy: jasmine.Spy; + + const identityUserMock = { username: 'mock-username', firstName: 'fake-identity-first-name', lastName: 'fake-identity-last-name', email: 'fakeIdentity@email.com' }; + + setupTestBed({ + imports: [ + CoreModule.forRoot() + ], + providers: [ProcessFilterCloudService, UserPreferenceCloudService, IdentityUserService] + }); + + beforeEach(async(() => { + service = TestBed.get(ProcessFilterCloudService); + userPreferenceCloudService = TestBed.get(UserPreferenceCloudService); + identityUserService = TestBed.get(IdentityUserService); + createPreferenceSpy = spyOn(userPreferenceCloudService, 'createPreference').and.returnValue(of(fakeProcessCloudFilters)); + updatePreferenceSpy = spyOn(userPreferenceCloudService, 'updatePreference').and.returnValue(of(fakeProcessCloudFilters)); + getPreferenceByKeySpy = spyOn(userPreferenceCloudService, 'getPreferenceByKey').and.returnValue(of(fakeProcessCloudFilters)); + getPreferencesSpy = spyOn(userPreferenceCloudService, 'getPreferences').and.returnValue(of(fakeProcessCloudFilterEntries)); + getCurrentUserInfoSpy = spyOn(identityUserService, 'getCurrentUserInfo').and.returnValue(identityUserMock); + })); + + it('should create ProcessFilterCloudService instance', () => { + expect(service).toBeDefined(); + }); + + it('should create processfilter key by using appName and the username', (done) => { + service.getProcessFilters('mock-appName').subscribe((res: any) => { + expect(res).toBeDefined(); + expect(getCurrentUserInfoSpy).toHaveBeenCalled(); + done(); + }); + }); + + it('should create default process filters', (done) => { + getPreferencesSpy.and.returnValue(of(fakeEmptyProcessCloudFilterEntries)); + service.getProcessFilters('mock-appName').subscribe((res: any) => { + expect(res).toBeDefined(); + expect(res).not.toBeNull(); + expect(res.length).toBe(3); + + expect(res[0].appName).toBe('mock-appName'); + expect(res[0].id).toBe('1'); + expect(res[0].name).toBe('MOCK_PROCESS_NAME_1'); + expect(res[0].status).toBe('MOCK_ALL'); + + expect(res[1].appName).toBe('mock-appName'); + expect(res[1].id).toBe('2'); + expect(res[1].name).toBe('MOCK_PROCESS_NAME_2'); + expect(res[1].status).toBe('MOCK-RUNNING'); + + expect(res[2].appName).toBe('mock-appName'); + expect(res[2].id).toBe('3'); + expect(res[2].name).toBe('MOCK_PROCESS_NAME_3'); + expect(res[2].status).toBe('MOCK-COMPLETED'); + done(); + }); + expect(createPreferenceSpy).toHaveBeenCalled(); + }); + + it('should fetch the process filters if filters are available', (done) => { + service.getProcessFilters('mock-appName').subscribe((res: any) => { + expect(res).toBeDefined(); + expect(res).not.toBeNull(); + expect(res.length).toBe(3); + + expect(res[0].appName).toBe('mock-appName'); + expect(res[0].id).toBe('1'); + expect(res[0].name).toBe('MOCK_PROCESS_NAME_1'); + expect(res[0].status).toBe('MOCK_ALL'); + + expect(res[1].appName).toBe('mock-appName'); + expect(res[1].id).toBe('2'); + expect(res[1].name).toBe('MOCK_PROCESS_NAME_2'); + expect(res[1].status).toBe('MOCK-RUNNING'); + + expect(res[2].appName).toBe('mock-appName'); + expect(res[2].id).toBe('3'); + expect(res[2].name).toBe('MOCK_PROCESS_NAME_3'); + expect(res[2].status).toBe('MOCK-COMPLETED'); + done(); + }); + expect(getPreferencesSpy).toHaveBeenCalled(); + }); + + it('should create the process filters in case the filters are not exist in the user preferences', (done) => { + getPreferencesSpy.and.returnValue(of(fakeProcessCloudFilterWithDifferentEntries)); + service.getProcessFilters('mock-appName').subscribe((res: any) => { + expect(res).toBeDefined(); + expect(res).not.toBeNull(); + expect(res.length).toBe(3); + + expect(res[0].appName).toBe('mock-appName'); + expect(res[0].id).toBe('1'); + expect(res[0].name).toBe('MOCK_PROCESS_NAME_1'); + expect(res[0].status).toBe('MOCK_ALL'); + + expect(res[1].appName).toBe('mock-appName'); + expect(res[1].id).toBe('2'); + expect(res[1].name).toBe('MOCK_PROCESS_NAME_2'); + expect(res[1].status).toBe('MOCK-RUNNING'); + + expect(res[2].appName).toBe('mock-appName'); + expect(res[2].id).toBe('3'); + expect(res[2].name).toBe('MOCK_PROCESS_NAME_3'); + expect(res[2].status).toBe('MOCK-COMPLETED'); + done(); + }); + expect(getPreferencesSpy).toHaveBeenCalled(); + expect(createPreferenceSpy).toHaveBeenCalled(); + }); + + it('should return filter by process filter id', (done) => { + service.getFilterById('mock-appName', '2').subscribe((res: any) => { + expect(res).toBeDefined(); + expect(res).not.toBeNull(); + expect(res.appName).toBe('mock-appName'); + expect(res.id).toBe('2'); + expect(res.name).toBe('MOCK_PROCESS_NAME_2'); + expect(res.status).toBe('MOCK-RUNNING'); + done(); + }); + expect(getPreferenceByKeySpy).toHaveBeenCalled(); + }); + + it('should add process filter if filter is not exist in the filters', (done) => { + getPreferenceByKeySpy.and.returnValue(of([])); + service.getFilterById('mock-appName', '2').subscribe((res: any) => { + expect(res).toBeDefined(); + expect(res).not.toBeNull(); + expect(res.appName).toBe('mock-appName'); + expect(res.id).toBe('2'); + expect(res.name).toBe('MOCK_PROCESS_NAME_2'); + expect(res.status).toBe('MOCK-RUNNING'); + done(); + }); + }); + + it('should update filter', (done) => { + service.updateFilter(fakeProcessFilter).subscribe((res: any) => { + expect(res).toBeDefined(); + expect(res).not.toBeNull(); + expect(res.length).toBe(3); + expect(res[0].appName).toBe('mock-appName'); + expect(res[1].appName).toBe('mock-appName'); + expect(res[2].appName).toBe('mock-appName'); + done(); + }); + }); + + it('should create process filter when trying to update in case filter is not exist in the filters', (done) => { + getPreferenceByKeySpy.and.returnValue(of([])); + service.updateFilter(fakeProcessFilter).subscribe((res: any) => { + expect(res).toBeDefined(); + expect(res).not.toBeNull(); + expect(res.length).toBe(3); + expect(res[0].appName).toBe('mock-appName'); + expect(res[1].appName).toBe('mock-appName'); + expect(res[2].appName).toBe('mock-appName'); + done(); + }); + expect(createPreferenceSpy).toHaveBeenCalled(); + }); + + it('should delete filter', (done) => { + service.deleteFilter(fakeProcessFilter).subscribe((res: any) => { + expect(res).toBeDefined(); + done(); + }); + expect(updatePreferenceSpy).toHaveBeenCalled(); + }); +}); diff --git a/lib/process-services-cloud/src/lib/process/process-filters/services/process-filter-cloud.service.ts b/lib/process-services-cloud/src/lib/process/process-filters/services/process-filter-cloud.service.ts index c74d578214..e6db30639a 100644 --- a/lib/process-services-cloud/src/lib/process/process-filters/services/process-filter-cloud.service.ts +++ b/lib/process-services-cloud/src/lib/process/process-filters/services/process-filter-cloud.service.ts @@ -15,10 +15,12 @@ * limitations under the License. */ -import { StorageService, IdentityUserService, IdentityUserModel } from '@alfresco/adf-core'; +import { IdentityUserService, IdentityUserModel } from '@alfresco/adf-core'; import { Injectable } from '@angular/core'; -import { Observable, BehaviorSubject } from 'rxjs'; +import { Observable, of, BehaviorSubject, throwError } from 'rxjs'; import { ProcessFilterCloudModel } from '../models/process-filter-cloud.model'; +import { UserPreferenceCloudService } from '../../../services/public-api'; +import { switchMap, map, catchError } from 'rxjs/operators'; @Injectable() export class ProcessFilterCloudService { @@ -27,41 +29,43 @@ export class ProcessFilterCloudService { filters$: Observable; constructor( - private storage: StorageService, + private preferenceService: UserPreferenceCloudService, private identityUserService: IdentityUserService) { this.filtersSubject = new BehaviorSubject([]); this.filters$ = this.filtersSubject.asObservable(); } /** - * Creates and returns the default filters for a process app. + * Creates and returns the default process instance filters for a app. * @param appName Name of the target app - * @returns Observable of default filters just created + * @returns Observable of default process instance filters just created or created filters */ private createDefaultFilters(appName: string) { - const allProcessesFilter = this.getAllProcessesFilter(appName); - this.addFilter(allProcessesFilter); - const runningProcessesFilter = this.getRunningProcessesFilter(appName); - this.addFilter(runningProcessesFilter); - const completedProcessesFilter = this.getCompletedProcessesFilter(appName); - this.addFilter(completedProcessesFilter); + const key: string = this.prepareKey(appName); + this.preferenceService.getPreferences(appName).pipe( + switchMap((response: any) => { + const preferences = (response && response.list && response.list.entries) ? response.list.entries : []; + if (!this.hasPreferences(preferences)) { + return this.createProcessFilters(appName, key, this.defaultProcessFilters(appName)); + } else if (!this.hasProcessFilters(preferences, key)) { + return this.createProcessFilters(appName, key, this.defaultProcessFilters(appName)); + } else { + return of(this.findFiltersByKeyInPrefrences(preferences, key)); + } + }), + catchError((err) => this.handleProcessError(err)) + ).subscribe((filters) => { + this.addFiltersToStream(filters); + }); } /** * Gets all process instance filters for a process app. * @param appName Name of the target app - * @returns Observable of process filter details + * @returns Observable of process filters details */ getProcessFilters(appName: string): Observable { - const user: IdentityUserModel = this.identityUserService.getCurrentUserInfo(); - const key = `process-filters-${appName}-${user.username}`; - const filters = JSON.parse(this.storage.getItem(key) || '[]'); - - if (filters.length === 0) { - this.createDefaultFilters(appName); - } else { - this.addFiltersToStream(filters); - } + this.createDefaultFilters(appName); return this.filters$; } @@ -69,119 +73,213 @@ export class ProcessFilterCloudService { * Get process instance filter for given filter id * @param appName Name of the target app * @param id Id of the target process instance filter - * @returns Details of process filter + * @returns Observable of process instance filter details */ - getProcessFilterById(appName: string, id: string): ProcessFilterCloudModel { - const user: IdentityUserModel = this.identityUserService.getCurrentUserInfo(); - const key = `process-filters-${appName}-${user.username}`; - let filters = []; - filters = JSON.parse(this.storage.getItem(key)) || []; - return filters.filter((filterTmp: ProcessFilterCloudModel) => id === filterTmp.id)[0]; + getFilterById(appName: string, id: string): Observable { + const key: string = this.prepareKey(appName); + return this.getProcessFiltersByKey(appName, key).pipe( + switchMap((filters: ProcessFilterCloudModel[]) => { + if (filters && filters.length === 0) { + return this.createProcessFilters(appName, key, this.defaultProcessFilters(appName)); + } else { + return of(filters); + } + }), + map((filters: ProcessFilterCloudModel[]) => { + return filters.filter((filter: ProcessFilterCloudModel) => { + return filter.id === id; + })[0]; + }), + catchError((err) => this.handleProcessError(err)) + ); } /** * Adds a new process instance filter * @param filter The new filter to add - * @returns Details of process filter just added + * @returns Obervable of process instance filters with newly added filter */ - addFilter(filter: ProcessFilterCloudModel) { - const user: IdentityUserModel = this.identityUserService.getCurrentUserInfo(); - const key = `process-filters-${filter.appName}-${user.username}`; - const storedFilters = JSON.parse(this.storage.getItem(key) || '[]'); - - storedFilters.push(filter); - this.storage.setItem(key, JSON.stringify(storedFilters)); - - this.addFiltersToStream(storedFilters); + addFilter(newFilter: ProcessFilterCloudModel): Observable { + const key: string = this.prepareKey(newFilter.appName); + return this.getProcessFiltersByKey(newFilter.appName, key).pipe( + switchMap((filters: ProcessFilterCloudModel[]) => { + if (filters && filters.length === 0) { + return this.createProcessFilters(newFilter.appName, key, [newFilter]); + } else { + filters.push(newFilter); + return this.preferenceService.updatePreference(newFilter.appName, key, filters); + } + }), + map((filters: ProcessFilterCloudModel[]) => { + this.addFiltersToStream(filters); + return filters; + }), + catchError((err) => this.handleProcessError(err)) + ); } /** * Update process instance filter * @param filter The new filter to update + * @returns Observable of process instance filters with updated filter */ - updateFilter(filter: ProcessFilterCloudModel) { - const user: IdentityUserModel = this.identityUserService.getCurrentUserInfo(); - const key = `process-filters-${filter.appName}-${user.username}`; - if (key) { - const filters = JSON.parse(this.storage.getItem(key) || '[]'); - const itemIndex = filters.findIndex((flt: ProcessFilterCloudModel) => flt.id === filter.id); - filters[itemIndex] = filter; - this.storage.setItem(key, JSON.stringify(filters)); - this.addFiltersToStream(filters); - } + updateFilter(updatedFilter: ProcessFilterCloudModel): Observable { + const key: string = this.prepareKey(updatedFilter.appName); + return this.getProcessFiltersByKey(updatedFilter.appName, key).pipe( + switchMap((filters: any) => { + if (filters && filters.length === 0) { + return this.createProcessFilters(updatedFilter.appName, key, [updatedFilter]); + } else { + const itemIndex = filters.findIndex((filter: ProcessFilterCloudModel) => filter.id === updatedFilter.id); + filters[itemIndex] = updatedFilter; + return this.updateProcessFilters(updatedFilter.appName, key, filters); + } + }), + map((updatedFilters: ProcessFilterCloudModel[]) => { + this.addFiltersToStream(updatedFilters); + return updatedFilters; + }), + catchError((err) => this.handleProcessError(err)) + ); } /** * Delete process instance filter * @param filter The new filter to delete + * @returns Observable of process instance filters without deleted filter */ - deleteFilter(filter: ProcessFilterCloudModel) { - const user: IdentityUserModel = this.identityUserService.getCurrentUserInfo(); - const key = `process-filters-${filter.appName}-${user.username}`; - if (key) { - let filters = JSON.parse(this.storage.getItem(key) || '[]'); - filters = filters.filter((item) => item.id !== filter.id); - this.storage.setItem(key, JSON.stringify(filters)); - if (filters.length === 0) { - this.createDefaultFilters(filter.appName); - } else { + deleteFilter(deletedFilter: ProcessFilterCloudModel): Observable { + const key = this.prepareKey(deletedFilter.appName); + return this.getProcessFiltersByKey(deletedFilter.appName, key).pipe( + switchMap((filters: any) => { + if (filters && filters.length > 0) { + filters = filters.filter((filter: ProcessFilterCloudModel) => filter.id !== deletedFilter.id); + return this.updateProcessFilters(deletedFilter.appName, key, filters); + } + }), + map((filters: ProcessFilterCloudModel[]) => { this.addFiltersToStream(filters); - } - } + return filters; + }), + catchError((err) => this.handleProcessError(err)) + ); } /** - * Creates and returns a filter for "All" Process instances. - * @param appName Name of the target app - * @returns The newly created filter + * Checks user preference are empty or not + * @param preferences User preferences of the target app + * @returns Boolean value if the preferences are not empty */ - getAllProcessesFilter(appName: string): ProcessFilterCloudModel { - return new ProcessFilterCloudModel({ - name: 'ADF_CLOUD_PROCESS_FILTERS.ALL_PROCESSES', - key: 'all-processes', - icon: 'adjust', - appName: appName, - sort: 'startDate', - status: '', - order: 'DESC' - }); + private hasPreferences(preferences: any): boolean { + return preferences && preferences.length > 0; } /** - * Creates and returns a filter for "Running" Process instances. - * @param appName Name of the target app - * @returns The newly created filter + * Checks for process instance filters in given user preferences + * @param preferences User preferences of the target app + * @param key Key of the process instance filters + * @param filters Details of create filter + * @returns Boolean value if the preference has process instance filters */ - getRunningProcessesFilter(appName: string): ProcessFilterCloudModel { - return new ProcessFilterCloudModel({ - name: 'ADF_CLOUD_PROCESS_FILTERS.RUNNING_PROCESSES', - icon: 'inbox', - key: 'running-processes', - appName: appName, - sort: 'startDate', - status: 'RUNNING', - order: 'DESC' - }); + private hasProcessFilters(preferences: any, key: string): boolean { + const filters = preferences.find((filter: any) => { return filter.entry.key === key; }); + return (filters && filters.entry) ? JSON.parse(filters.entry.value).length > 0 : false; } /** - * Creates and returns a filter for "Completed" Process instances. + * Calls create preference api to create process instance filters * @param appName Name of the target app - * @returns The newly created filter + * @param key Key of the process instance filters + * @param filters Details of new process instance filter + * @returns Observable of created process instance filters */ - getCompletedProcessesFilter(appName: string): ProcessFilterCloudModel { - return new ProcessFilterCloudModel({ - name: 'ADF_CLOUD_PROCESS_FILTERS.COMPLETED_PROCESSES', - icon: 'done', - key: 'completed-processes', - appName: appName, - sort: 'startDate', - status: 'COMPLETED', - order: 'DESC' - }); + private createProcessFilters(appName: string, key: string, filters: ProcessFilterCloudModel[]): Observable { + return this.preferenceService.createPreference(appName, key, filters); } - private addFiltersToStream(filters: ProcessFilterCloudModel []) { + /** + * Calls get preference api to get process instance filter by preference key + * @param appName Name of the target app + * @param key Key of the process instance filters + * @returns Observable of process instance filters + */ + private getProcessFiltersByKey(appName: string, key: string): Observable { + return this.preferenceService.getPreferenceByKey(appName, key); + } + + /** + * Calls update preference api to update process instance filter + * @param appName Name of the target app + * @param key Key of the process instance filters + * @param filters Details of update filter + * @returns Observable of updated process instance filters + */ + private updateProcessFilters(appName: string, key: string, filters: ProcessFilterCloudModel[]): Observable { + return this.preferenceService.updatePreference(appName, key, filters); + } + + /** + * Creates a uniq key with appName and username + * @param appName Name of the target app + * @returns String of process instance filters preference key + */ + private prepareKey(appName: string): string { + const user: IdentityUserModel = this.identityUserService.getCurrentUserInfo(); + return `process-filters-${appName}-${user.username}`; + } + + /** + * Finds and returns the process instance filters from preferences + * @param appName Name of the target app + * @returns Array of ProcessFilterCloudModel + */ + private findFiltersByKeyInPrefrences(preferences: any, key: string): ProcessFilterCloudModel[] { + const result = preferences.find((filter: any) => { return filter.entry.key === key; }); + return result && result.entry ? JSON.parse(result.entry.value) : []; + } + + private addFiltersToStream(filters: ProcessFilterCloudModel[]) { this.filtersSubject.next(filters); } + + private handleProcessError(error: any) { + return throwError(error || 'Server error'); + } + + /** + * Creates and returns the default filters for a process app. + * @param appName Name of the target app + * @returns Array of ProcessFilterCloudModel + */ + private defaultProcessFilters(appName: string): ProcessFilterCloudModel[] { + return [ + new ProcessFilterCloudModel({ + name: 'ADF_CLOUD_PROCESS_FILTERS.ALL_PROCESSES', + key: 'all-processes', + icon: 'adjust', + appName: appName, + sort: 'startDate', + status: '', + order: 'DESC' + }), + new ProcessFilterCloudModel({ + name: 'ADF_CLOUD_PROCESS_FILTERS.RUNNING_PROCESSES', + icon: 'inbox', + key: 'running-processes', + appName: appName, + sort: 'startDate', + status: 'RUNNING', + order: 'DESC' + }), + new ProcessFilterCloudModel({ + name: 'ADF_CLOUD_PROCESS_FILTERS.COMPLETED_PROCESSES', + icon: 'done', + key: 'completed-processes', + appName: appName, + sort: 'startDate', + status: 'COMPLETED', + order: 'DESC' + }) + ]; + } } diff --git a/lib/process-services-cloud/src/lib/services/public-api.ts b/lib/process-services-cloud/src/lib/services/public-api.ts index a1ee695bf0..ec1caf78ed 100644 --- a/lib/process-services-cloud/src/lib/services/public-api.ts +++ b/lib/process-services-cloud/src/lib/services/public-api.ts @@ -16,3 +16,4 @@ */ export * from './identity-user.service'; +export * from './user-preference.cloud.service'; diff --git a/lib/process-services-cloud/src/lib/services/user-preference.cloud.service.spec.ts b/lib/process-services-cloud/src/lib/services/user-preference.cloud.service.spec.ts new file mode 100644 index 0000000000..0896cfa643 --- /dev/null +++ b/lib/process-services-cloud/src/lib/services/user-preference.cloud.service.spec.ts @@ -0,0 +1,201 @@ +/*! + * @license + * Copyright 2019 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { TestBed, async } from '@angular/core/testing'; + +import { UserPreferenceCloudService } from './user-preference.cloud.service'; +import { setupTestBed, CoreModule, AlfrescoApiServiceMock, AppConfigService, LogService, AlfrescoApiService } from '@alfresco/adf-core'; +import { mockPreferences, getMockPreference, createMockPreference, updateMockPreference } from '../mock/user-preference.mock'; + +describe('PreferenceService', () => { + let service: UserPreferenceCloudService; + let alfrescoApiMock: AlfrescoApiServiceMock; + let getInstanceSpy: jasmine.Spy; + + const errorResponse = { + error: 'Mock Error', + state: 404, stateText: 'Not Found' + }; + + function apiMock(mockResponse) { + return { + oauth2Auth: { + callCustomApi: () => { + return Promise.resolve(mockResponse); + } + } + }; + } + + const apiErrorMock = { + oauth2Auth: { + callCustomApi: () => Promise.reject(errorResponse) + } + }; + + setupTestBed({ + imports: [ + CoreModule.forRoot() + ], + providers: [ + UserPreferenceCloudService, AppConfigService, LogService, + { provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock } + ] + }); + + beforeEach(async(() => { + service = TestBed.get(UserPreferenceCloudService); + alfrescoApiMock = TestBed.get(AlfrescoApiService); + service.contextRoot = 'http://{{domain}}.com'; + getInstanceSpy = spyOn(alfrescoApiMock, 'getInstance').and.returnValue(apiMock(mockPreferences)); + })); + + it('should create UserPreferenceCloudService instance', () => { + expect(service).toBeTruthy(); + }); + + it('should return the preferences', (done) => { + service.getPreferences('mock-app-name').subscribe((res: any) => { + expect(res).toBeDefined(); + expect(res).not.toBeNull(); + expect(res.list.entries.length).toBe(3); + expect(res.list.entries[0].entry.key).toBe('mock-preference-key-1'); + expect(res.list.entries[0].entry.value.length).toBe(2); + expect(res.list.entries[0].entry.value[0].username).toBe('mock-username-1'); + expect(res.list.entries[0].entry.value[0].firstName).toBe('mock-firstname-1'); + + expect(res.list.entries[1].entry.key).toBe('mock-preference-key-2'); + expect(res.list.entries[1].entry.value).toBe('my mock preference value'); + + expect(res.list.entries[2].entry.key).toBe('mock-preference-key-3'); + expect(res.list.entries[2].entry.value.appName).toBe('mock-appName'); + expect(res.list.entries[2].entry.value.state).toBe('MOCK-COMPLETED'); + done(); + }); + }); + + it('Should not fetch preferences if error occurred', () => { + getInstanceSpy.and.returnValue(apiErrorMock); + service.getPreferences('mock-app-name') + .subscribe( + (preferences) => fail('expected an error, not preferences'), + (error) => { + expect(error.state).toEqual(404); + expect(error.stateText).toEqual('Not Found'); + expect(error.error).toEqual('Mock Error'); + } + ); + }); + + it('should return the preference by key', (done) => { + getInstanceSpy.and.returnValue(apiMock(getMockPreference)); + service.getPreferenceByKey('mock-app-name', 'mock-preference-key').subscribe((res: any) => { + expect(res).toBeDefined(); + expect(res).not.toBeNull(); + expect(res.length).toBe(2); + expect(res[0].appName).toBe('mock-appName'); + expect(res[0].firstName).toBe('mock-firstname-1'); + expect(res[1].appName).toBe('mock-appName'); + expect(res[1].username).toBe('mock-username-2'); + done(); + }); + }); + + it('Should not fetch preference by key if error occurred', () => { + getInstanceSpy.and.returnValue(apiErrorMock); + service.getPreferenceByKey('mock-app-name', 'mock-preference-key') + .subscribe( + (preference) => fail('expected an error, not preference'), + (error) => { + expect(error.state).toEqual(404); + expect(error.stateText).toEqual('Not Found'); + expect(error.error).toEqual('Mock Error'); + } + ); + }); + + it('should create preference', (done) => { + getInstanceSpy.and.returnValue(apiMock(createMockPreference)); + service.createPreference('mock-app-name', 'mock-preference-key', createMockPreference).subscribe((res: any) => { + expect(res).toBeDefined(); + expect(res).not.toBeNull(); + expect(res).toBe(createMockPreference); + expect(res.appName).toBe('mock-appName'); + expect(res.name).toBe('create-preference'); + done(); + }); + }); + + it('Should not create preference if error occurred', () => { + getInstanceSpy.and.returnValue(apiErrorMock); + service.createPreference('mock-app-name', 'mock-preference-key', createMockPreference) + .subscribe( + (preference) => fail('expected an error, not to create preference'), + (error) => { + expect(error.state).toEqual(404); + expect(error.stateText).toEqual('Not Found'); + expect(error.error).toEqual('Mock Error'); + } + ); + }); + + it('should update preference', (done) => { + getInstanceSpy.and.returnValue(apiMock(updateMockPreference)); + service.updatePreference('mock-app-name', 'mock-preference-key', updateMockPreference).subscribe((res: any) => { + expect(res).toBeDefined(); + expect(res).not.toBeNull(); + expect(res).toBe(updateMockPreference); + expect(res.appName).toBe('mock-appName'); + expect(res.name).toBe('update-preference'); + done(); + }); + }); + + it('Should not update preference if error occurred', () => { + getInstanceSpy.and.returnValue(apiErrorMock); + service.createPreference('mock-app-name', 'mock-preference-key', updateMockPreference) + .subscribe( + (preference) => fail('expected an error, not to update preference'), + (error) => { + expect(error.state).toEqual(404); + expect(error.stateText).toEqual('Not Found'); + expect(error.error).toEqual('Mock Error'); + } + ); + }); + + it('should delete preference', (done) => { + getInstanceSpy.and.returnValue(apiMock('')); + service.deletePreference('mock-app-name', 'mock-preference-key').subscribe((res: any) => { + expect(res).toBeDefined(); + done(); + }); + }); + + it('Should not delete preference if error occurred', () => { + getInstanceSpy.and.returnValue(apiErrorMock); + service.deletePreference('mock-app-name', 'mock-preference-key') + .subscribe( + (preference) => fail('expected an error, not to delete preference'), + (error) => { + expect(error.state).toEqual(404); + expect(error.stateText).toEqual('Not Found'); + expect(error.error).toEqual('Mock Error'); + } + ); + }); +}); diff --git a/lib/process-services-cloud/src/lib/services/user-preference.cloud.service.ts b/lib/process-services-cloud/src/lib/services/user-preference.cloud.service.ts new file mode 100644 index 0000000000..64079992e9 --- /dev/null +++ b/lib/process-services-cloud/src/lib/services/user-preference.cloud.service.ts @@ -0,0 +1,150 @@ +/*! + * @license + * Copyright 2019 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Injectable } from '@angular/core'; +import { BaseCloudService } from './base-cloud.service'; +import { AlfrescoApiService, AppConfigService, LogService } from '@alfresco/adf-core'; +import { from, throwError, Observable } from 'rxjs'; +import { catchError } from 'rxjs/operators'; + +@Injectable() +export class UserPreferenceCloudService extends BaseCloudService { + + contentTypes = ['application/json']; + accepts = ['application/json']; + + constructor( + private alfrescoApiService: AlfrescoApiService, + private appConfigService: AppConfigService, + private logService: LogService) { + super(); + } + + /** + * Gets user preferences + * @param appName Name of the target app + * @returns List of user preferences + */ + getPreferences(appName: string): Observable { + if (appName || appName === '') { + const uri = this.buildPreferenceServiceUri(appName); + return from(this.alfrescoApiService.getInstance() + .oauth2Auth.callCustomApi(uri, 'GET', + null, null, null, + null, null, this.contentTypes, + this.accepts, null, null) + ); + } else { + this.logService.error('Appname is mandatory for querying preferences'); + return throwError('Appname not configured'); + } + } + + /** + * Gets user preference. + * @param appName Name of the target app + * @param key Key of the target preference + * @returns Observable of user preferences + */ + getPreferenceByKey(appName: string, key: string): Observable { + if (appName || appName === '') { + const uri = this.buildPreferenceServiceUri(appName) + '/' + `${key}`; + return from( + this.alfrescoApiService.getInstance() + .oauth2Auth.callCustomApi(uri, 'GET', + null, null, null, + null, null, this.contentTypes, + this.accepts, null, null) + ).pipe(catchError((error) => throwError(error))); + } else { + this.logService.error('Appname and key are mandatory for querying preference'); + return throwError('Appname not configured'); + } + } + + /** + * Creates user preference. + * @param appName Name of the target app + * @param key Key of the target preference + * @newPreference Details of new user preference + * @returns Observable of created user preferences + */ + createPreference(appName: string, key: string, newPreference: any): Observable { + if (appName || appName === '') { + const uri = this.buildPreferenceServiceUri(appName) + '/' + `${key}`; + const requestPayload = JSON.stringify(newPreference); + return from(this.alfrescoApiService.getInstance() + .oauth2Auth.callCustomApi(uri, 'PUT', + null, null, + null, null, requestPayload, + this.contentTypes, this.accepts, + Object, null, null) + ).pipe( + catchError((err) => this.handleProcessError(err)) + ); + } else { + this.logService.error('Appname and key are mandatory for creating preference'); + return throwError('Appname not configured'); + } + } + + /** + * Updates user preference. + * @param appName Name of the target app + * @param key Key of the target preference + * @param updatedPreference Details of updated preference + * @returns Observable of updated user preferences + */ + updatePreference(appName: string, key: string, updatedPreference: any): Observable { + return this.createPreference(appName, key, updatedPreference); + } + + /** + * Deletes user preference by given preference key. + * @param appName Name of the target app + * @param key Key of the target preference + * @returns Observable of delete operation status + */ + deletePreference(appName: string, key: string): Observable { + if (appName || appName === '') { + const uri = this.buildPreferenceServiceUri(appName) + '/' + `${key}`; + return from(this.alfrescoApiService.getInstance() + .oauth2Auth.callCustomApi(uri, 'DELETE', + null, null, null, + null, null, this.contentTypes, + this.accepts, null, null, null) + ); + } else { + this.logService.error('Appname and key are mandatory to delete preference'); + return throwError('Appname not configured'); + } + } + + /** + * Creates preference uri + * @param appName Name of the target app + * @returns String of preference service uri + */ + private buildPreferenceServiceUri(appName: string): string { + this.contextRoot = this.appConfigService.get('bpmHost', ''); + return `${this.getBasePath(appName)}/preference/v1/preferences`; + } + + private handleProcessError(error: any) { + return throwError(error || 'Server error'); + } +} From a4fc53a7425cef5333c2f9755e92f2f354c34fe2 Mon Sep 17 00:00:00 2001 From: Suzana Dirla Date: Fri, 5 Jul 2019 16:52:39 +0300 Subject: [PATCH 036/140] [ADF-4708] fileSize header is now left aligned with bottom cells (#4902) --- .../components/datatable/datatable.component.scss | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/core/datatable/components/datatable/datatable.component.scss b/lib/core/datatable/components/datatable/datatable.component.scss index 387115f206..c2a6b7f3da 100644 --- a/lib/core/datatable/components/datatable/datatable.component.scss +++ b/lib/core/datatable/components/datatable/datatable.component.scss @@ -333,6 +333,11 @@ &.adf-datatable__header--sorted-desc::before { content: '\e5db'; } + &.adf-datatable-cell--fileSize.adf-datatable__header--sorted-asc::before, + &.adf-datatable-cell--fileSize.adf-datatable__header--sorted-desc::before { + left: -3px; + right: -3px; + } &.adf-datatable-checkbox { display: flex; @@ -389,6 +394,9 @@ padding: 17px 10px 10px; } } + &--fileSize .adf-datatable-cell-value { + padding: 0; + } &:focus { outline-offset: -1px; From cf761ba0b26f55791a937741bb043f91c2760267 Mon Sep 17 00:00:00 2001 From: Eugenio Romano Date: Mon, 8 Jul 2019 10:21:48 +0100 Subject: [PATCH 037/140] Cleaning test IMG viewer component (#4906) * promote use setupTestbed * fix sanatize transform img * fix sanatize transform img --- docs/core/components/icon.component.md | 83 ---- .../components/imgViewer.component.html | 2 +- .../components/imgViewer.component.spec.ts | 426 ++++++++++-------- .../viewer/components/imgViewer.component.ts | 6 +- .../dynamic.component.spec.ts | 15 +- 5 files changed, 242 insertions(+), 290 deletions(-) delete mode 100644 docs/core/components/icon.component.md diff --git a/docs/core/components/icon.component.md b/docs/core/components/icon.component.md deleted file mode 100644 index 7566c9aa74..0000000000 --- a/docs/core/components/icon.component.md +++ /dev/null @@ -1,83 +0,0 @@ ---- -Title: Icon Component -Added: v3.0.0 -Status: Active -Last reviewed: 2019-02-08 ---- - -# [Icon Component](../../../lib/core/icon/icon.component.ts "Defined in icon.component.ts") - -Provides a universal way of rendering registered and named icons. - -## Basic usage - -```html - - - - - - - - -``` - -## Class members - -### Properties - -| Name | Type | Default value | Description | -| ---- | ---- | ------------- | ----------- | -| color | `ThemePalette` | | Theme color palette for the component. | -| value | `string` | | Icon value, which can be either a ligature name or a custom icon in the format `[namespace]:[name]`. | - -## Details - -You can register custom SVG files as named icons in the format `[namespace]:[name]`. - -The example below shows how to register a new icon named `adf:move_file` -that points to an external file within the `assets` folder: - -```ts -import { Component, OnInit } from '@angular/core'; -import { MatIconRegistry } from '@angular/material'; -import { DomSanitizer } from '@angular/platform-browser'; - -@Component({...}) -export class AppComponent implements OnInit { - - constructor( - private matIconRegistry: MatIconRegistry, - private sanitizer: DomSanitizer - ) {} - - ngOnInit() { - this.matIconRegistry.addSvgIconInNamespace( - 'adf', - 'move_file', - this.sanitizer.bypassSecurityTrustResourceUrl( - './assets/images/adf-move-file-24px.svg' - ) - ); - } -} -``` - -In the HTML, you can now use the icon as shown below: - -```html - -``` - -### Thumbnail Service - -You can also reference the icons registered with the [Thumbnail Service](../services/thumbnail.service.md) -using the `adf:` namespace. - -```html - -``` - -## See also - -- [Thumbnail service](../services/thumbnail.service.md) diff --git a/lib/core/viewer/components/imgViewer.component.html b/lib/core/viewer/components/imgViewer.component.html index 10eea07bb9..f4f5814413 100644 --- a/lib/core/viewer/components/imgViewer.component.html +++ b/lib/core/viewer/components/imgViewer.component.html @@ -1,4 +1,4 @@ -