mirror of
https://github.com/Alfresco/alfresco-content-app.git
synced 2025-05-12 17:04:46 +00:00
[ACS-4865] setup and enable code coverage for all projects (#3074)
This commit is contained in:
parent
86c0bbb998
commit
9609393d1e
22
README.md
22
README.md
@ -39,6 +39,28 @@ npm start content-ce -- --configuration=adf
|
|||||||
|
|
||||||
Changing the ADF code results in the recompilation and hot-reloading of the ACA application.
|
Changing the ADF code results in the recompilation and hot-reloading of the ACA application.
|
||||||
|
|
||||||
|
## Unit Tests
|
||||||
|
|
||||||
|
Use standard Angular CLI commands to test the projects:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
ng test <project>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Code Coverage
|
||||||
|
|
||||||
|
The projects are already configured to produce code coverage reports in console and HTML output.
|
||||||
|
|
||||||
|
You can view HTML reports in the `./coverage/<project>` folder.
|
||||||
|
|
||||||
|
When working with unit testing and code coverage improvement, you can run unit tests in the "live reload" mode:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
ng test <project> --watch
|
||||||
|
```
|
||||||
|
|
||||||
|
Upon changing unit tests code, you can track the coverage results either in the console output, or by reloading the HTML report in the browser.
|
||||||
|
|
||||||
## Triggering the build to use specific branch of ADF with CI flags
|
## Triggering the build to use specific branch of ADF with CI flags
|
||||||
|
|
||||||
You can create commits with the intention of running the build pipeline using a specific branch of ADF. To achieve this, you need to add a specific CI flag in your commit message:
|
You can create commits with the intention of running the build pipeline using a specific branch of ADF. To achieve this, you need to add a specific CI flag in your commit message:
|
||||||
|
@ -367,6 +367,7 @@
|
|||||||
"test": {
|
"test": {
|
||||||
"builder": "@angular-devkit/build-angular:karma",
|
"builder": "@angular-devkit/build-angular:karma",
|
||||||
"options": {
|
"options": {
|
||||||
|
"codeCoverage": true,
|
||||||
"main": "projects/adf-office-services-ext/src/test.ts",
|
"main": "projects/adf-office-services-ext/src/test.ts",
|
||||||
"tsConfig": "projects/adf-office-services-ext/tsconfig.spec.json",
|
"tsConfig": "projects/adf-office-services-ext/tsconfig.spec.json",
|
||||||
"karmaConfig": "projects/adf-office-services-ext/karma.conf.js"
|
"karmaConfig": "projects/adf-office-services-ext/karma.conf.js"
|
||||||
@ -413,6 +414,7 @@
|
|||||||
"test": {
|
"test": {
|
||||||
"builder": "@angular-devkit/build-angular:karma",
|
"builder": "@angular-devkit/build-angular:karma",
|
||||||
"options": {
|
"options": {
|
||||||
|
"codeCoverage": true,
|
||||||
"main": "projects/aca-shared/test.ts",
|
"main": "projects/aca-shared/test.ts",
|
||||||
"tsConfig": "projects/aca-shared/tsconfig.spec.json",
|
"tsConfig": "projects/aca-shared/tsconfig.spec.json",
|
||||||
"karmaConfig": "projects/aca-shared/karma.conf.js"
|
"karmaConfig": "projects/aca-shared/karma.conf.js"
|
||||||
@ -465,6 +467,7 @@
|
|||||||
"test": {
|
"test": {
|
||||||
"builder": "@angular-devkit/build-angular:karma",
|
"builder": "@angular-devkit/build-angular:karma",
|
||||||
"options": {
|
"options": {
|
||||||
|
"codeCoverage": true,
|
||||||
"main": "projects/aca-about/src/test.ts",
|
"main": "projects/aca-about/src/test.ts",
|
||||||
"tsConfig": "projects/aca-about/tsconfig.spec.json",
|
"tsConfig": "projects/aca-about/tsconfig.spec.json",
|
||||||
"karmaConfig": "projects/aca-about/karma.conf.js"
|
"karmaConfig": "projects/aca-about/karma.conf.js"
|
||||||
@ -506,6 +509,7 @@
|
|||||||
"test": {
|
"test": {
|
||||||
"builder": "@angular-devkit/build-angular:karma",
|
"builder": "@angular-devkit/build-angular:karma",
|
||||||
"options": {
|
"options": {
|
||||||
|
"codeCoverage": true,
|
||||||
"main": "projects/aca-folder-rules/src/test.ts",
|
"main": "projects/aca-folder-rules/src/test.ts",
|
||||||
"tsConfig": "projects/aca-folder-rules/tsconfig.spec.json",
|
"tsConfig": "projects/aca-folder-rules/tsconfig.spec.json",
|
||||||
"karmaConfig": "projects/aca-folder-rules/karma.conf.js"
|
"karmaConfig": "projects/aca-folder-rules/karma.conf.js"
|
||||||
@ -554,6 +558,7 @@
|
|||||||
"test": {
|
"test": {
|
||||||
"builder": "@angular-devkit/build-angular:karma",
|
"builder": "@angular-devkit/build-angular:karma",
|
||||||
"options": {
|
"options": {
|
||||||
|
"codeCoverage": true,
|
||||||
"main": "projects/aca-content/src/test.ts",
|
"main": "projects/aca-content/src/test.ts",
|
||||||
"tsConfig": "projects/aca-content/tsconfig.spec.json",
|
"tsConfig": "projects/aca-content/tsconfig.spec.json",
|
||||||
"karmaConfig": "projects/aca-content/karma.conf.js",
|
"karmaConfig": "projects/aca-content/karma.conf.js",
|
||||||
@ -605,6 +610,7 @@
|
|||||||
"test": {
|
"test": {
|
||||||
"builder": "@angular-devkit/build-angular:karma",
|
"builder": "@angular-devkit/build-angular:karma",
|
||||||
"options": {
|
"options": {
|
||||||
|
"codeCoverage": true,
|
||||||
"main": "projects/aca-viewer/src/test.ts",
|
"main": "projects/aca-viewer/src/test.ts",
|
||||||
"tsConfig": "projects/aca-viewer/tsconfig.spec.json",
|
"tsConfig": "projects/aca-viewer/tsconfig.spec.json",
|
||||||
"karmaConfig": "projects/aca-viewer/karma.conf.js"
|
"karmaConfig": "projects/aca-viewer/karma.conf.js"
|
||||||
@ -648,6 +654,7 @@
|
|||||||
"test": {
|
"test": {
|
||||||
"builder": "@angular-devkit/build-angular:karma",
|
"builder": "@angular-devkit/build-angular:karma",
|
||||||
"options": {
|
"options": {
|
||||||
|
"codeCoverage": true,
|
||||||
"main": "projects/aca-preview/src/test.ts",
|
"main": "projects/aca-preview/src/test.ts",
|
||||||
"tsConfig": "projects/aca-preview/tsconfig.spec.json",
|
"tsConfig": "projects/aca-preview/tsconfig.spec.json",
|
||||||
"karmaConfig": "projects/aca-preview/karma.conf.js"
|
"karmaConfig": "projects/aca-preview/karma.conf.js"
|
||||||
|
@ -1,25 +1,22 @@
|
|||||||
// Karma configuration file, see link for more information
|
// Karma configuration file, see link for more information
|
||||||
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||||
// process.env.CHROME_BIN = require('puppeteer').executablePath();
|
|
||||||
|
|
||||||
module.exports = function(config) {
|
const { join } = require('path');
|
||||||
config.set({
|
const { constants } = require('karma');
|
||||||
|
|
||||||
|
module.exports = () => {
|
||||||
|
return {
|
||||||
basePath: '',
|
basePath: '',
|
||||||
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
||||||
plugins: [
|
plugins: [
|
||||||
require('karma-jasmine'),
|
require('karma-jasmine'),
|
||||||
require('karma-chrome-launcher'),
|
require('karma-chrome-launcher'),
|
||||||
require('karma-jasmine-html-reporter'),
|
require('karma-jasmine-html-reporter'),
|
||||||
require('karma-coverage-istanbul-reporter'),
|
require('karma-coverage'),
|
||||||
require('karma-mocha-reporter'),
|
require('karma-mocha-reporter'),
|
||||||
require('@angular-devkit/build-angular/plugins/karma')
|
require('@angular-devkit/build-angular/plugins/karma')
|
||||||
],
|
],
|
||||||
files: [
|
files: [
|
||||||
{
|
|
||||||
pattern:
|
|
||||||
'./node_modules/@angular/material/prebuilt-themes/indigo-pink.css',
|
|
||||||
watched: false
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
pattern:
|
pattern:
|
||||||
'./node_modules/@alfresco/adf-core/bundles/assets/adf-core/i18n/en.json',
|
'./node_modules/@alfresco/adf-core/bundles/assets/adf-core/i18n/en.json',
|
||||||
@ -46,18 +43,36 @@ module.exports = function(config) {
|
|||||||
'/base/node_modules/@alfresco/adf-content-services/bundles/assets/adf-content-services/i18n/en.json'
|
'/base/node_modules/@alfresco/adf-content-services/bundles/assets/adf-content-services/i18n/en.json'
|
||||||
},
|
},
|
||||||
client: {
|
client: {
|
||||||
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
jasmine: {
|
||||||
|
// you can add configuration options for Jasmine here
|
||||||
|
// the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
|
||||||
|
// for example, you can disable the random execution with `random: false`
|
||||||
|
// or set a specific seed with `seed: 4321`
|
||||||
|
},
|
||||||
|
clearContext: false, // leave Jasmine Spec Runner output visible in browser
|
||||||
},
|
},
|
||||||
coverageIstanbulReporter: {
|
jasmineHtmlReporter: {
|
||||||
dir: require('path').join(__dirname, 'coverage'),
|
suppressAll: true, // removes the duplicated traces
|
||||||
reports: ['html', 'lcovonly'],
|
},
|
||||||
fixWebpackSourcePaths: true
|
|
||||||
|
coverageReporter: {
|
||||||
|
dir: join(__dirname, './coverage'),
|
||||||
|
subdir: '.',
|
||||||
|
reporters: [{ type: 'html' }, { type: 'text-summary' }],
|
||||||
|
check: {
|
||||||
|
global: {
|
||||||
|
statements: 75,
|
||||||
|
branches: 67,
|
||||||
|
functions: 73,
|
||||||
|
lines: 75
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
reporters: ['mocha', 'kjhtml'],
|
reporters: ['mocha', 'kjhtml'],
|
||||||
port: 9876,
|
port: 9876,
|
||||||
colors: true,
|
colors: true,
|
||||||
logLevel: config.LOG_INFO,
|
logLevel: constants.LOG_INFO,
|
||||||
autoWatch: true,
|
autoWatch: true,
|
||||||
browsers: ['ChromeHeadless'],
|
browsers: ['ChromeHeadless'],
|
||||||
customLaunchers: {
|
customLaunchers: {
|
||||||
@ -65,19 +80,15 @@ module.exports = function(config) {
|
|||||||
base: 'Chrome',
|
base: 'Chrome',
|
||||||
flags: [
|
flags: [
|
||||||
'--no-sandbox',
|
'--no-sandbox',
|
||||||
// '--headless',
|
'--headless',
|
||||||
'--disable-gpu',
|
'--disable-gpu',
|
||||||
'--remote-debugging-port=9222'
|
'--remote-debugging-port=9222'
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
singleRun: true,
|
singleRun: true,
|
||||||
captureTimeout: 180000,
|
restartOnFileChange: true,
|
||||||
browserDisconnectTimeout: 180000,
|
|
||||||
browserDisconnectTolerance: 3,
|
|
||||||
browserNoActivityTimeout: 300000,
|
|
||||||
|
|
||||||
// workaround for alfresco-js-api builds
|
// workaround for alfresco-js-api builds
|
||||||
webpack: { node: { fs: 'empty' } }
|
webpack: { node: { fs: 'empty' } }
|
||||||
});
|
};
|
||||||
};
|
};
|
||||||
|
58
package-lock.json
generated
58
package-lock.json
generated
@ -12916,6 +12916,64 @@
|
|||||||
"which": "^1.2.1"
|
"which": "^1.2.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"karma-coverage": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/karma-coverage/-/karma-coverage-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-gPVdoZBNDZ08UCzdMHHhEImKrw1+PAOQOIiffv1YsvxFhBjqvo/SVXNk4tqn1SYqX0BJZT6S/59zgxiBe+9OuA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"istanbul-lib-coverage": "^3.2.0",
|
||||||
|
"istanbul-lib-instrument": "^5.1.0",
|
||||||
|
"istanbul-lib-report": "^3.0.0",
|
||||||
|
"istanbul-lib-source-maps": "^4.0.1",
|
||||||
|
"istanbul-reports": "^3.0.5",
|
||||||
|
"minimatch": "^3.0.4"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"istanbul-lib-coverage": {
|
||||||
|
"version": "3.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz",
|
||||||
|
"integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"istanbul-lib-source-maps": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz",
|
||||||
|
"integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"debug": "^4.1.1",
|
||||||
|
"istanbul-lib-coverage": "^3.0.0",
|
||||||
|
"source-map": "^0.6.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"istanbul-reports": {
|
||||||
|
"version": "3.1.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz",
|
||||||
|
"integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"html-escaper": "^2.0.0",
|
||||||
|
"istanbul-lib-report": "^3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"minimatch": {
|
||||||
|
"version": "3.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||||
|
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"brace-expansion": "^1.1.7"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"source-map": {
|
||||||
|
"version": "0.6.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||||
|
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||||
|
"dev": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"karma-coverage-istanbul-reporter": {
|
"karma-coverage-istanbul-reporter": {
|
||||||
"version": "3.0.3",
|
"version": "3.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/karma-coverage-istanbul-reporter/-/karma-coverage-istanbul-reporter-3.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/karma-coverage-istanbul-reporter/-/karma-coverage-istanbul-reporter-3.0.3.tgz",
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
"build.release": "npm run build -- --configuration=production,release",
|
"build.release": "npm run build -- --configuration=production,release",
|
||||||
"build-libs": "ng build aca-shared && ng build adf-office-services-ext && ng build aca-about && ng build aca-viewer && ng build aca-preview && ng build aca-folder-rules && ng build aca-content",
|
"build-libs": "ng build aca-shared && ng build adf-office-services-ext && ng build aca-about && ng build aca-viewer && ng build aca-preview && ng build aca-folder-rules && ng build aca-content",
|
||||||
"test": "ng test",
|
"test": "ng test",
|
||||||
"test:ci": "ng test adf-office-services-ext && ng test content-ce --code-coverage",
|
|
||||||
"lint": "NODE_OPTIONS=--max_old_space_size=4096 ng lint",
|
"lint": "NODE_OPTIONS=--max_old_space_size=4096 ng lint",
|
||||||
"update-webdriver": "./scripts/update-webdriver.sh",
|
"update-webdriver": "./scripts/update-webdriver.sh",
|
||||||
"e2e": "npm run update-webdriver && protractor $SUITE",
|
"e2e": "npm run update-webdriver && protractor $SUITE",
|
||||||
@ -102,6 +101,7 @@
|
|||||||
"jasmine-spec-reporter": "~5.0.0",
|
"jasmine-spec-reporter": "~5.0.0",
|
||||||
"karma": "^6.4.1",
|
"karma": "^6.4.1",
|
||||||
"karma-chrome-launcher": "~3.1.1",
|
"karma-chrome-launcher": "~3.1.1",
|
||||||
|
"karma-coverage": "^2.2.0",
|
||||||
"karma-coverage-istanbul-reporter": "^3.0.3",
|
"karma-coverage-istanbul-reporter": "^3.0.3",
|
||||||
"karma-jasmine": "~5.1.0",
|
"karma-jasmine": "~5.1.0",
|
||||||
"karma-jasmine-html-reporter": "^2.0.0",
|
"karma-jasmine-html-reporter": "^2.0.0",
|
||||||
|
@ -1,32 +1,15 @@
|
|||||||
// Karma configuration file, see link for more information
|
// Karma configuration file, see link for more information
|
||||||
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||||
|
const { join } = require('path');
|
||||||
|
const getBaseKarmaConfig = require('../../karma.conf');
|
||||||
|
|
||||||
module.exports = function (config) {
|
module.exports = function (config) {
|
||||||
|
const baseConfig = getBaseKarmaConfig();
|
||||||
config.set({
|
config.set({
|
||||||
basePath: '',
|
...baseConfig,
|
||||||
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
coverageReporter: {
|
||||||
plugins: [
|
...baseConfig.coverageReporter,
|
||||||
require('karma-jasmine'),
|
dir: join(__dirname, '../../coverage/aca-about'),
|
||||||
require('karma-chrome-launcher'),
|
|
||||||
require('karma-jasmine-html-reporter'),
|
|
||||||
require('karma-coverage-istanbul-reporter'),
|
|
||||||
require('@angular-devkit/build-angular/plugins/karma')
|
|
||||||
],
|
|
||||||
client: {
|
|
||||||
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
|
||||||
},
|
},
|
||||||
coverageIstanbulReporter: {
|
|
||||||
dir: require('path').join(__dirname, '../../coverage/aca-about'),
|
|
||||||
reports: ['html', 'lcovonly', 'text-summary'],
|
|
||||||
fixWebpackSourcePaths: true
|
|
||||||
},
|
|
||||||
reporters: ['progress', 'kjhtml'],
|
|
||||||
port: 9876,
|
|
||||||
colors: true,
|
|
||||||
logLevel: config.LOG_INFO,
|
|
||||||
autoWatch: true,
|
|
||||||
browsers: ['Chrome'],
|
|
||||||
singleRun: true,
|
|
||||||
restartOnFileChange: true
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -1,32 +1,15 @@
|
|||||||
// Karma configuration file, see link for more information
|
// Karma configuration file, see link for more information
|
||||||
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||||
|
const { join } = require('path');
|
||||||
|
const getBaseKarmaConfig = require('../../karma.conf');
|
||||||
|
|
||||||
module.exports = function (config) {
|
module.exports = function (config) {
|
||||||
|
const baseConfig = getBaseKarmaConfig();
|
||||||
config.set({
|
config.set({
|
||||||
basePath: '',
|
...baseConfig,
|
||||||
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
coverageReporter: {
|
||||||
plugins: [
|
...baseConfig.coverageReporter,
|
||||||
require('karma-jasmine'),
|
dir: join(__dirname, '../../coverage/aca-content'),
|
||||||
require('karma-chrome-launcher'),
|
|
||||||
require('karma-jasmine-html-reporter'),
|
|
||||||
require('karma-coverage-istanbul-reporter'),
|
|
||||||
require('@angular-devkit/build-angular/plugins/karma')
|
|
||||||
],
|
|
||||||
client: {
|
|
||||||
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
|
||||||
},
|
},
|
||||||
coverageIstanbulReporter: {
|
|
||||||
dir: require('path').join(__dirname, '../../coverage/aca-content'),
|
|
||||||
reports: ['html', 'lcovonly', 'text-summary'],
|
|
||||||
fixWebpackSourcePaths: true
|
|
||||||
},
|
|
||||||
reporters: ['progress', 'kjhtml'],
|
|
||||||
port: 9876,
|
|
||||||
colors: true,
|
|
||||||
logLevel: config.LOG_INFO,
|
|
||||||
autoWatch: true,
|
|
||||||
browsers: ['Chrome'],
|
|
||||||
singleRun: true,
|
|
||||||
restartOnFileChange: true
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { TranslateService, TranslatePipe } from '@ngx-translate/core';
|
import { TranslatePipe, TranslateModule } from '@ngx-translate/core';
|
||||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
import {
|
import {
|
||||||
TranslationService,
|
TranslationService,
|
||||||
@ -44,7 +44,6 @@ import { EffectsModule } from '@ngrx/effects';
|
|||||||
import { MaterialModule } from '../material.module';
|
import { MaterialModule } from '../material.module';
|
||||||
import { INITIAL_STATE } from '../store/initial-state';
|
import { INITIAL_STATE } from '../store/initial-state';
|
||||||
import { TranslatePipeMock } from './translate-pipe.directive';
|
import { TranslatePipeMock } from './translate-pipe.directive';
|
||||||
import { TranslateServiceMock } from '@alfresco/aca-shared';
|
|
||||||
import { BehaviorSubject, Observable, of } from 'rxjs';
|
import { BehaviorSubject, Observable, of } from 'rxjs';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
@ -53,6 +52,7 @@ import { BehaviorSubject, Observable, of } from 'rxjs';
|
|||||||
HttpClientModule,
|
HttpClientModule,
|
||||||
RouterTestingModule,
|
RouterTestingModule,
|
||||||
MaterialModule,
|
MaterialModule,
|
||||||
|
TranslateModule.forRoot(),
|
||||||
StoreModule.forRoot(
|
StoreModule.forRoot(
|
||||||
{ app: appReducer },
|
{ app: appReducer },
|
||||||
{
|
{
|
||||||
@ -71,7 +71,6 @@ import { BehaviorSubject, Observable, of } from 'rxjs';
|
|||||||
providers: [
|
providers: [
|
||||||
{ provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock },
|
{ provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock },
|
||||||
{ provide: TranslationService, useClass: TranslationMock },
|
{ provide: TranslationService, useClass: TranslationMock },
|
||||||
{ provide: TranslateService, useClass: TranslateServiceMock },
|
|
||||||
{ provide: TranslatePipe, useClass: TranslatePipeMock },
|
{ provide: TranslatePipe, useClass: TranslatePipeMock },
|
||||||
{
|
{
|
||||||
provide: DiscoveryApiService,
|
provide: DiscoveryApiService,
|
||||||
|
@ -1,32 +1,15 @@
|
|||||||
// Karma configuration file, see link for more information
|
// Karma configuration file, see link for more information
|
||||||
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||||
|
const { join } = require('path');
|
||||||
|
const getBaseKarmaConfig = require('../../karma.conf');
|
||||||
|
|
||||||
module.exports = function (config) {
|
module.exports = function (config) {
|
||||||
|
const baseConfig = getBaseKarmaConfig();
|
||||||
config.set({
|
config.set({
|
||||||
basePath: '',
|
...baseConfig,
|
||||||
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
coverageReporter: {
|
||||||
plugins: [
|
...baseConfig.coverageReporter,
|
||||||
require('karma-jasmine'),
|
dir: join(__dirname, '../../coverage/aca-folder-rules'),
|
||||||
require('karma-chrome-launcher'),
|
|
||||||
require('karma-jasmine-html-reporter'),
|
|
||||||
require('karma-coverage-istanbul-reporter'),
|
|
||||||
require('@angular-devkit/build-angular/plugins/karma')
|
|
||||||
],
|
|
||||||
client: {
|
|
||||||
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
|
||||||
},
|
},
|
||||||
coverageIstanbulReporter: {
|
|
||||||
dir: require('path').join(__dirname, '../../coverage/aca-folder-rules'),
|
|
||||||
reports: ['html', 'lcovonly', 'text-summary'],
|
|
||||||
fixWebpackSourcePaths: true
|
|
||||||
},
|
|
||||||
reporters: ['progress', 'kjhtml'],
|
|
||||||
port: 9876,
|
|
||||||
colors: true,
|
|
||||||
logLevel: config.LOG_INFO,
|
|
||||||
autoWatch: true,
|
|
||||||
browsers: ['Chrome'],
|
|
||||||
singleRun: true,
|
|
||||||
restartOnFileChange: true
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -1,32 +1,15 @@
|
|||||||
// Karma configuration file, see link for more information
|
// Karma configuration file, see link for more information
|
||||||
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||||
|
const { join } = require('path');
|
||||||
|
const getBaseKarmaConfig = require('../../karma.conf');
|
||||||
|
|
||||||
module.exports = function (config) {
|
module.exports = function (config) {
|
||||||
|
const baseConfig = getBaseKarmaConfig();
|
||||||
config.set({
|
config.set({
|
||||||
basePath: '',
|
...baseConfig,
|
||||||
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
coverageReporter: {
|
||||||
plugins: [
|
...baseConfig.coverageReporter,
|
||||||
require('karma-jasmine'),
|
dir: join(__dirname, '../../coverage/aca-preview'),
|
||||||
require('karma-chrome-launcher'),
|
|
||||||
require('karma-jasmine-html-reporter'),
|
|
||||||
require('karma-coverage-istanbul-reporter'),
|
|
||||||
require('@angular-devkit/build-angular/plugins/karma')
|
|
||||||
],
|
|
||||||
client: {
|
|
||||||
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
|
||||||
},
|
},
|
||||||
coverageIstanbulReporter: {
|
|
||||||
dir: require('path').join(__dirname, '../../coverage/aca-preview'),
|
|
||||||
reports: ['html', 'lcovonly', 'text-summary'],
|
|
||||||
fixWebpackSourcePaths: true
|
|
||||||
},
|
|
||||||
reporters: ['progress', 'kjhtml'],
|
|
||||||
port: 9876,
|
|
||||||
colors: true,
|
|
||||||
logLevel: config.LOG_INFO,
|
|
||||||
autoWatch: true,
|
|
||||||
browsers: ['Chrome'],
|
|
||||||
singleRun: true,
|
|
||||||
restartOnFileChange: true
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -38,11 +38,11 @@ import { UploadService, NodesApiService, DiscoveryApiService } from '@alfresco/a
|
|||||||
import { AppState, ClosePreviewAction } from '@alfresco/aca-shared/store';
|
import { AppState, ClosePreviewAction } from '@alfresco/aca-shared/store';
|
||||||
import { PreviewComponent } from './preview.component';
|
import { PreviewComponent } from './preview.component';
|
||||||
import { BehaviorSubject, Observable, of, throwError } from 'rxjs';
|
import { BehaviorSubject, Observable, of, throwError } from 'rxjs';
|
||||||
import { ContentApiService, AppHookService, TranslateServiceMock, DocumentBasePageService } from '@alfresco/aca-shared';
|
import { ContentApiService, AppHookService, DocumentBasePageService } from '@alfresco/aca-shared';
|
||||||
import { Store, StoreModule } from '@ngrx/store';
|
import { Store, StoreModule } from '@ngrx/store';
|
||||||
import { Node, NodePaging, FavoritePaging, SharedLinkPaging, PersonEntry, ResultSetPaging, RepositoryInfo, NodeEntry } from '@alfresco/js-api';
|
import { Node, NodePaging, FavoritePaging, SharedLinkPaging, PersonEntry, ResultSetPaging, RepositoryInfo, NodeEntry } from '@alfresco/js-api';
|
||||||
import { PreviewModule } from '../preview.module';
|
import { PreviewModule } from '../preview.module';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { RouterTestingModule } from '@angular/router/testing';
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
import { HttpClientModule } from '@angular/common/http';
|
import { HttpClientModule } from '@angular/common/http';
|
||||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
@ -115,6 +115,7 @@ describe('PreviewComponent', () => {
|
|||||||
NoopAnimationsModule,
|
NoopAnimationsModule,
|
||||||
HttpClientModule,
|
HttpClientModule,
|
||||||
RouterTestingModule,
|
RouterTestingModule,
|
||||||
|
TranslateModule.forRoot(),
|
||||||
StoreModule.forRoot(
|
StoreModule.forRoot(
|
||||||
{ app: (state) => state },
|
{ app: (state) => state },
|
||||||
{
|
{
|
||||||
@ -133,7 +134,6 @@ describe('PreviewComponent', () => {
|
|||||||
providers: [
|
providers: [
|
||||||
{ provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock },
|
{ provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock },
|
||||||
{ provide: TranslationService, useClass: TranslationMock },
|
{ provide: TranslationService, useClass: TranslationMock },
|
||||||
{ provide: TranslateService, useClass: TranslateServiceMock },
|
|
||||||
{ provide: DocumentBasePageService, useVale: new DocumentBasePageServiceMock() },
|
{ provide: DocumentBasePageService, useVale: new DocumentBasePageServiceMock() },
|
||||||
{
|
{
|
||||||
provide: DiscoveryApiService,
|
provide: DiscoveryApiService,
|
||||||
|
@ -1,33 +1,15 @@
|
|||||||
// Karma configuration file, see link for more information
|
// Karma configuration file, see link for more information
|
||||||
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||||
|
const { join } = require('path');
|
||||||
|
const getBaseKarmaConfig = require('../../karma.conf');
|
||||||
|
|
||||||
module.exports = function (config) {
|
module.exports = function (config) {
|
||||||
|
const baseConfig = getBaseKarmaConfig();
|
||||||
config.set({
|
config.set({
|
||||||
basePath: '',
|
...baseConfig,
|
||||||
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
coverageReporter: {
|
||||||
plugins: [
|
...baseConfig.coverageReporter,
|
||||||
require('karma-jasmine'),
|
dir: join(__dirname, '../../coverage/aca-shared'),
|
||||||
require('karma-chrome-launcher'),
|
|
||||||
require('karma-jasmine-html-reporter'),
|
|
||||||
require('karma-coverage-istanbul-reporter'),
|
|
||||||
require('karma-mocha-reporter'),
|
|
||||||
require('@angular-devkit/build-angular/plugins/karma')
|
|
||||||
],
|
|
||||||
client: {
|
|
||||||
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
|
||||||
},
|
},
|
||||||
coverageIstanbulReporter: {
|
|
||||||
dir: require('path').join(__dirname, '../../coverage/aca-shared'),
|
|
||||||
reports: ['html', 'lcovonly'],
|
|
||||||
fixWebpackSourcePaths: true
|
|
||||||
},
|
|
||||||
reporters: ['mocha', 'kjhtml'],
|
|
||||||
port: 9876,
|
|
||||||
colors: true,
|
|
||||||
logLevel: config.LOG_INFO,
|
|
||||||
autoWatch: true,
|
|
||||||
browsers: ['Chrome'],
|
|
||||||
singleRun: true,
|
|
||||||
restartOnFileChange: true
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -143,12 +143,14 @@ export abstract class PageComponent implements OnInit, OnDestroy, OnChanges {
|
|||||||
}
|
}
|
||||||
|
|
||||||
imageResolver(row: ShareDataRow): string | null {
|
imageResolver(row: ShareDataRow): string | null {
|
||||||
if (isLocked(row.node)) {
|
if (row) {
|
||||||
return 'assets/images/baseline-lock-24px.svg';
|
if (isLocked(row.node)) {
|
||||||
}
|
return 'assets/images/baseline-lock-24px.svg';
|
||||||
|
}
|
||||||
|
|
||||||
if (isLibrary(row.node)) {
|
if (isLibrary(row.node)) {
|
||||||
return 'assets/images/baseline-library_books-24px.svg';
|
return 'assets/images/baseline-library_books-24px.svg';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@ -181,7 +183,7 @@ export abstract class PageComponent implements OnInit, OnDestroy, OnChanges {
|
|||||||
return location.href.includes('viewer:view');
|
return location.href.includes('viewer:view');
|
||||||
}
|
}
|
||||||
|
|
||||||
onSortingChanged(event) {
|
onSortingChanged(event: any) {
|
||||||
this.filterSorting = event.detail.key + '-' + event.detail.direction;
|
this.filterSorting = event.detail.key + '-' + event.detail.direction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,6 +38,7 @@ import { HttpClientModule } from '@angular/common/http';
|
|||||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
import { RouterTestingModule } from '@angular/router/testing';
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
import { EffectsModule } from '@ngrx/effects';
|
import { EffectsModule } from '@ngrx/effects';
|
||||||
|
import { Subscription } from 'rxjs';
|
||||||
|
|
||||||
export const INITIAL_APP_STATE: AppState = {
|
export const INITIAL_APP_STATE: AppState = {
|
||||||
appName: 'Alfresco Content Application',
|
appName: 'Alfresco Content Application',
|
||||||
@ -98,6 +99,14 @@ class TestComponent extends PageComponent {
|
|||||||
constructor(store: Store<AppStore>, extensions: AppExtensionService, content: DocumentBasePageService) {
|
constructor(store: Store<AppStore>, extensions: AppExtensionService, content: DocumentBasePageService) {
|
||||||
super(store, extensions, content);
|
super(store, extensions, content);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addSubscription(entry: Subscription) {
|
||||||
|
this.subscriptions.push(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
getSubscriptions(): Subscription[] {
|
||||||
|
return this.subscriptions;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('PageComponent', () => {
|
describe('PageComponent', () => {
|
||||||
@ -341,4 +350,66 @@ describe('Info Drawer state', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should not resolve custom image', () => {
|
||||||
|
expect(component.imageResolver(null)).toBe(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should resolve custom image for locked node', () => {
|
||||||
|
const row: any = {
|
||||||
|
node: {
|
||||||
|
entry: {
|
||||||
|
isLocked: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(component.imageResolver(row)).toBe('assets/images/baseline-lock-24px.svg');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should resolve custom image for a library', () => {
|
||||||
|
const row: any = {
|
||||||
|
node: {
|
||||||
|
entry: {
|
||||||
|
nodeType: 'st:site'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(component.imageResolver(row)).toBe('assets/images/baseline-library_books-24px.svg');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should track elements by action id ', () => {
|
||||||
|
const action: any = { id: 'action1' };
|
||||||
|
expect(component.trackByActionId(0, action)).toBe('action1');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should track elements by id ', () => {
|
||||||
|
const action: any = { id: 'action1' };
|
||||||
|
expect(component.trackById(0, action)).toBe('action1');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should track elements by column id ', () => {
|
||||||
|
const action: any = { id: 'action1' };
|
||||||
|
expect(component.trackByColumnId(0, action)).toBe('action1');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should cleanup subscriptions on destroy', () => {
|
||||||
|
const sub = jasmine.createSpyObj('sub', ['unsubscribe']);
|
||||||
|
|
||||||
|
expect(component.getSubscriptions().length).toBe(0);
|
||||||
|
|
||||||
|
component.addSubscription(sub);
|
||||||
|
expect(component.getSubscriptions().length).toBe(1);
|
||||||
|
|
||||||
|
component.ngOnDestroy();
|
||||||
|
expect(sub.unsubscribe).toHaveBeenCalled();
|
||||||
|
expect(component.getSubscriptions().length).toBe(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update filter sorting', () => {
|
||||||
|
const event = new CustomEvent('sorting-changed', { detail: { key: 'name', direction: 'asc' } });
|
||||||
|
component.onSortingChanged(event);
|
||||||
|
expect(component.filterSorting).toBe('name-asc');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -23,21 +23,21 @@
|
|||||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Injectable } from '@angular/core';
|
import { LockedByComponent } from './locked-by.component';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
|
||||||
import { Observable, of } from 'rxjs';
|
|
||||||
|
|
||||||
@Injectable()
|
describe('LockedByComponent', () => {
|
||||||
export class TranslateServiceMock extends TranslateService {
|
it('should evaluate label text', () => {
|
||||||
constructor() {
|
const component = new LockedByComponent();
|
||||||
super(null, null, null, null, null, null, true, null, null);
|
component.node = {
|
||||||
}
|
entry: {
|
||||||
|
properties: {
|
||||||
|
'cm:lockOwner': {
|
||||||
|
displayName: 'owner-name'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} as any
|
||||||
|
};
|
||||||
|
|
||||||
get(key: string | Array<string>): Observable<string | any> {
|
expect(component.text).toBe('owner-name');
|
||||||
return of(key);
|
});
|
||||||
}
|
});
|
||||||
|
|
||||||
instant(key: string | Array<string>): string | any {
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
}
|
|
@ -45,8 +45,6 @@ export class LockedByComponent {
|
|||||||
node: NodeEntry;
|
node: NodeEntry;
|
||||||
|
|
||||||
get text(): string {
|
get text(): string {
|
||||||
return (
|
return this.node?.entry?.properties?.['cm:lockOwner']?.displayName;
|
||||||
this.node && this.node.entry.properties && this.node.entry.properties['cm:lockOwner'] && this.node.entry.properties['cm:lockOwner'].displayName
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,9 @@ import { OpenInAppComponent } from './open-in-app.component';
|
|||||||
import { initialState, LibTestingModule } from '../../testing/lib-testing-module';
|
import { initialState, LibTestingModule } from '../../testing/lib-testing-module';
|
||||||
import { provideMockStore } from '@ngrx/store/testing';
|
import { provideMockStore } from '@ngrx/store/testing';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
import { MatIconTestingModule } from '@angular/material/icon/testing';
|
||||||
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
|
import { SharedModule } from '@alfresco/aca-shared';
|
||||||
|
|
||||||
describe('OpenInAppComponent', () => {
|
describe('OpenInAppComponent', () => {
|
||||||
let fixture: ComponentFixture<OpenInAppComponent>;
|
let fixture: ComponentFixture<OpenInAppComponent>;
|
||||||
@ -15,16 +18,15 @@ describe('OpenInAppComponent', () => {
|
|||||||
open: jasmine.createSpy('open')
|
open: jasmine.createSpy('open')
|
||||||
};
|
};
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(() => {
|
||||||
await TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
declarations: [OpenInAppComponent],
|
imports: [LibTestingModule, TranslateModule, SharedModule.forRoot(), MatIconModule, MatIconTestingModule],
|
||||||
imports: [LibTestingModule, TranslateModule],
|
|
||||||
providers: [
|
providers: [
|
||||||
provideMockStore({ initialState }),
|
provideMockStore({ initialState }),
|
||||||
{ provide: MAT_DIALOG_DATA, useValue: { redirectUrl: 'mockRedirectUrl' } },
|
{ provide: MAT_DIALOG_DATA, useValue: { redirectUrl: 'mockRedirectUrl' } },
|
||||||
{ provide: MatDialogRef, useValue: mockDialogRef }
|
{ provide: MatDialogRef, useValue: mockDialogRef }
|
||||||
]
|
]
|
||||||
}).compileComponents();
|
});
|
||||||
|
|
||||||
fixture = TestBed.createComponent(OpenInAppComponent);
|
fixture = TestBed.createComponent(OpenInAppComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
|
@ -23,10 +23,51 @@
|
|||||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
import { ToolbarActionComponent } from './toolbar-action.component';
|
import { ToolbarActionComponent } from './toolbar-action.component';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { HttpClientModule } from '@angular/common/http';
|
||||||
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
import { ToolbarButtonType } from '../toolbar-button/toolbar-button.component';
|
||||||
|
import { ChangeDetectorRef } from '@angular/core';
|
||||||
|
import { ContentActionType } from '@alfresco/adf-extensions';
|
||||||
|
import { IconModule } from '@alfresco/adf-core';
|
||||||
|
|
||||||
describe('ToolbarActionComponent', () => {
|
describe('ToolbarActionComponent', () => {
|
||||||
it('should be defined', () => {
|
let fixture: ComponentFixture<ToolbarActionComponent>;
|
||||||
expect(ToolbarActionComponent).toBeDefined();
|
let component: ToolbarActionComponent;
|
||||||
|
let changeDetectorRef: ChangeDetectorRef;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [CommonModule, HttpClientModule, TranslateModule.forRoot(), IconModule],
|
||||||
|
providers: [{ provide: ChangeDetectorRef, useValue: { markForCheck() {} } }],
|
||||||
|
declarations: [ToolbarActionComponent]
|
||||||
|
});
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(ToolbarActionComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
|
||||||
|
changeDetectorRef = TestBed.inject(ChangeDetectorRef);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be icon button by default', () => {
|
||||||
|
expect(component.type).toBe(ToolbarButtonType.ICON_BUTTON);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should force update UI on check for the viewer', () => {
|
||||||
|
component = new ToolbarActionComponent(changeDetectorRef);
|
||||||
|
const markForCheck = spyOn(changeDetectorRef, 'markForCheck');
|
||||||
|
|
||||||
|
component.actionRef = {
|
||||||
|
id: '-app.viewer',
|
||||||
|
type: ContentActionType.button,
|
||||||
|
actions: {
|
||||||
|
click: 'ON_CLICK'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
component.ngDoCheck();
|
||||||
|
expect(markForCheck).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -23,10 +23,69 @@
|
|||||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { ToolbarButtonComponent } from './toolbar-button.component';
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { ToolbarButtonComponent, ToolbarButtonType } from './toolbar-button.component';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { HttpClientModule } from '@angular/common/http';
|
||||||
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
import { IconModule, TranslationMock, TranslationService } from '@alfresco/adf-core';
|
||||||
|
import { Store } from '@ngrx/store';
|
||||||
|
import { of } from 'rxjs';
|
||||||
|
import { AppExtensionService } from '../../../services/app.extension.service';
|
||||||
|
import { ContentActionType } from '@alfresco/adf-extensions';
|
||||||
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
|
|
||||||
describe('ToolbarButtonComponent', () => {
|
describe('ToolbarButtonComponent', () => {
|
||||||
it('should be defined', () => {
|
let fixture: ComponentFixture<ToolbarButtonComponent>;
|
||||||
expect(ToolbarButtonComponent).toBeDefined();
|
let component: ToolbarButtonComponent;
|
||||||
|
let appExtensionService: AppExtensionService;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [CommonModule, HttpClientModule, TranslateModule.forRoot(), IconModule, MatButtonModule],
|
||||||
|
declarations: [ToolbarButtonComponent],
|
||||||
|
providers: [
|
||||||
|
{ provide: TranslationService, useClass: TranslationMock },
|
||||||
|
{ provide: AppExtensionService, useValue: { runActionById() {} } },
|
||||||
|
{
|
||||||
|
provide: Store,
|
||||||
|
useValue: {
|
||||||
|
dispatch: () => {},
|
||||||
|
select: () => of({ count: 1 })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(ToolbarButtonComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
appExtensionService = TestBed.inject(AppExtensionService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be icon button by default', () => {
|
||||||
|
expect(component.type).toBe(ToolbarButtonType.ICON_BUTTON);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should run action on click', async () => {
|
||||||
|
const runActionById = spyOn(appExtensionService, 'runActionById');
|
||||||
|
|
||||||
|
component.actionRef = {
|
||||||
|
id: 'button1',
|
||||||
|
type: ContentActionType.button,
|
||||||
|
actions: {
|
||||||
|
click: 'ON_CLICK'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
await fixture.whenStable();
|
||||||
|
|
||||||
|
const button: HTMLButtonElement = fixture.nativeElement.querySelector('[id="button1"]');
|
||||||
|
button.click();
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
await fixture.whenStable();
|
||||||
|
|
||||||
|
expect(runActionById).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -23,10 +23,98 @@
|
|||||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
import { ToolbarMenuItemComponent } from './toolbar-menu-item.component';
|
import { ToolbarMenuItemComponent } from './toolbar-menu-item.component';
|
||||||
|
import { AppExtensionService } from '../../../services/app.extension.service';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { HttpClientModule } from '@angular/common/http';
|
||||||
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
import { Store } from '@ngrx/store';
|
||||||
|
import { IconModule, TranslationMock, TranslationService } from '@alfresco/adf-core';
|
||||||
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
|
import { of } from 'rxjs';
|
||||||
|
import { ContentActionRef, ContentActionType } from '@alfresco/adf-extensions';
|
||||||
|
|
||||||
describe('ToolbarMenuItemComponent', () => {
|
describe('ToolbarMenuItemComponent', () => {
|
||||||
it('should be defined', () => {
|
let fixture: ComponentFixture<ToolbarMenuItemComponent>;
|
||||||
expect(ToolbarMenuItemComponent).toBeDefined();
|
let component: ToolbarMenuItemComponent;
|
||||||
|
let appExtensionService: AppExtensionService;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [CommonModule, HttpClientModule, TranslateModule.forRoot(), IconModule, MatButtonModule],
|
||||||
|
declarations: [ToolbarMenuItemComponent],
|
||||||
|
providers: [
|
||||||
|
{ provide: TranslationService, useClass: TranslationMock },
|
||||||
|
{ provide: AppExtensionService, useValue: { runActionById() {} } },
|
||||||
|
{
|
||||||
|
provide: Store,
|
||||||
|
useValue: {
|
||||||
|
dispatch: () => {},
|
||||||
|
select: () => of({ count: 1 })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(ToolbarMenuItemComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
appExtensionService = TestBed.inject(AppExtensionService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should run action on click', async () => {
|
||||||
|
const runActionById = spyOn(appExtensionService, 'runActionById');
|
||||||
|
|
||||||
|
component.actionRef = {
|
||||||
|
id: 'button1',
|
||||||
|
type: ContentActionType.button,
|
||||||
|
actions: {
|
||||||
|
click: 'ON_CLICK'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
await fixture.whenStable();
|
||||||
|
|
||||||
|
const button: HTMLButtonElement = fixture.nativeElement.querySelector('[id="button1"]');
|
||||||
|
button.click();
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
await fixture.whenStable();
|
||||||
|
|
||||||
|
expect(runActionById).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should run action with focus selector on click', async () => {
|
||||||
|
const runActionById = spyOn(appExtensionService, 'runActionById');
|
||||||
|
|
||||||
|
component.menuId = 'menu1';
|
||||||
|
component.actionRef = {
|
||||||
|
id: 'button1',
|
||||||
|
type: ContentActionType.button,
|
||||||
|
actions: {
|
||||||
|
click: 'ON_CLICK'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
await fixture.whenStable();
|
||||||
|
|
||||||
|
const button: HTMLButtonElement = fixture.nativeElement.querySelector('[id="button1"]');
|
||||||
|
button.click();
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
await fixture.whenStable();
|
||||||
|
|
||||||
|
expect(runActionById).toHaveBeenCalledWith('ON_CLICK', { focusedElementOnCloseSelector: '#menu1' });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should track elements by content action id', () => {
|
||||||
|
const contentActionRef: ContentActionRef = {
|
||||||
|
id: 'action1',
|
||||||
|
type: ContentActionType.button
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(component.trackByActionId(0, contentActionRef)).toBe('action1');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -28,7 +28,8 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|||||||
import { MaterialModule } from '@alfresco/adf-core';
|
import { MaterialModule } from '@alfresco/adf-core';
|
||||||
import { OverlayModule } from '@angular/cdk/overlay';
|
import { OverlayModule } from '@angular/cdk/overlay';
|
||||||
import { TranslateModule, TranslateLoader, TranslateFakeLoader } from '@ngx-translate/core';
|
import { TranslateModule, TranslateLoader, TranslateFakeLoader } from '@ngx-translate/core';
|
||||||
import { ContentActionRef } from '@alfresco/adf-extensions';
|
import { ContentActionRef, ContentActionType } from '@alfresco/adf-extensions';
|
||||||
|
import { QueryList } from '@angular/core';
|
||||||
|
|
||||||
describe('ToolbarMenuComponent', () => {
|
describe('ToolbarMenuComponent', () => {
|
||||||
let fixture: ComponentFixture<ToolbarMenuComponent>;
|
let fixture: ComponentFixture<ToolbarMenuComponent>;
|
||||||
@ -50,6 +51,7 @@ describe('ToolbarMenuComponent', () => {
|
|||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
component.matTrigger = jasmine.createSpyObj('MatMenuTrigger', ['closeMenu']);
|
component.matTrigger = jasmine.createSpyObj('MatMenuTrigger', ['closeMenu']);
|
||||||
component.actionRef = actions;
|
component.actionRef = actions;
|
||||||
|
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -59,4 +61,23 @@ describe('ToolbarMenuComponent', () => {
|
|||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(component.matTrigger.closeMenu).toHaveBeenCalled();
|
expect(component.matTrigger.closeMenu).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should populate underlying menu with toolbar items', () => {
|
||||||
|
component.toolbarMenuItems = new QueryList();
|
||||||
|
component.toolbarMenuItems.reset([{ menuItem: {} } as any]);
|
||||||
|
expect(component.toolbarMenuItems.length).toBe(1);
|
||||||
|
|
||||||
|
expect(component.menu._allItems.length).toBe(0);
|
||||||
|
component.ngAfterViewInit();
|
||||||
|
expect(component.menu._allItems.length).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should track elements by content action id', () => {
|
||||||
|
const contentActionRef: ContentActionRef = {
|
||||||
|
id: 'action1',
|
||||||
|
type: ContentActionType.button
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(component.trackByActionId(0, contentActionRef)).toBe('action1');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
51
projects/aca-shared/src/lib/routing/shared.guard.spec.ts
Normal file
51
projects/aca-shared/src/lib/routing/shared.guard.spec.ts
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Alfresco Example Content Application
|
||||||
|
*
|
||||||
|
* Copyright (C) 2005 - 2020 Alfresco Software Limited
|
||||||
|
*
|
||||||
|
* This file is part of the Alfresco Example Content Application.
|
||||||
|
* If the software was purchased under a paid Alfresco license, the terms of
|
||||||
|
* the paid license agreement will prevail. Otherwise, the software is
|
||||||
|
* provided under the following open source license terms:
|
||||||
|
*
|
||||||
|
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { of } from 'rxjs';
|
||||||
|
import { AppSharedRuleGuard } from './shared.guard';
|
||||||
|
|
||||||
|
describe('AppSharedRuleGuard', () => {
|
||||||
|
it('should allow activation if quick share is enabled', () => {
|
||||||
|
const store: any = {
|
||||||
|
select: () => of(true)
|
||||||
|
};
|
||||||
|
const guard = new AppSharedRuleGuard(store);
|
||||||
|
const emittedSpy = jasmine.createSpy('emitted');
|
||||||
|
|
||||||
|
guard.canActivate({} as any).subscribe(emittedSpy);
|
||||||
|
expect(emittedSpy).toHaveBeenCalledWith(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should allow child activation if quick share is enabled', () => {
|
||||||
|
const store: any = {
|
||||||
|
select: () => of(true)
|
||||||
|
};
|
||||||
|
const guard = new AppSharedRuleGuard(store);
|
||||||
|
const emittedSpy = jasmine.createSpy('emitted');
|
||||||
|
|
||||||
|
guard.canActivateChild({} as any).subscribe(emittedSpy);
|
||||||
|
expect(emittedSpy).toHaveBeenCalledWith(true);
|
||||||
|
});
|
||||||
|
});
|
@ -39,11 +39,11 @@ export class AppSharedRuleGuard implements CanActivate {
|
|||||||
this.isQuickShareEnabled$ = store.select(isQuickShareEnabled);
|
this.isQuickShareEnabled$ = store.select(isQuickShareEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
canActivate(_: ActivatedRouteSnapshot): Observable<boolean> | Promise<boolean> | boolean {
|
canActivate(_: ActivatedRouteSnapshot): Observable<boolean> {
|
||||||
return this.isQuickShareEnabled$;
|
return this.isQuickShareEnabled$;
|
||||||
}
|
}
|
||||||
|
|
||||||
canActivateChild(route: ActivatedRouteSnapshot): Observable<boolean> | Promise<boolean> | boolean {
|
canActivateChild(route: ActivatedRouteSnapshot): Observable<boolean> {
|
||||||
return this.canActivate(route);
|
return this.canActivate(route);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,10 +28,13 @@ import { AppConfigService } from '@alfresco/adf-core';
|
|||||||
import { AlfrescoOfficeExtensionService } from './alfresco-office-extension.service';
|
import { AlfrescoOfficeExtensionService } from './alfresco-office-extension.service';
|
||||||
import { provideMockStore } from '@ngrx/store/testing';
|
import { provideMockStore } from '@ngrx/store/testing';
|
||||||
import { initialState, LibTestingModule } from '../testing/lib-testing-module';
|
import { initialState, LibTestingModule } from '../testing/lib-testing-module';
|
||||||
|
import { Subject } from 'rxjs';
|
||||||
|
|
||||||
describe('AlfrescoOfficeExtensionService', () => {
|
describe('AlfrescoOfficeExtensionService', () => {
|
||||||
let appConfig: AppConfigService;
|
let appConfig: AppConfigService;
|
||||||
let service: AlfrescoOfficeExtensionService;
|
let service: AlfrescoOfficeExtensionService;
|
||||||
|
let onLoad$: Subject<any>;
|
||||||
|
|
||||||
const mock = () => {
|
const mock = () => {
|
||||||
let storage: { [key: string]: any } = {};
|
let storage: { [key: string]: any } = {};
|
||||||
return {
|
return {
|
||||||
@ -48,16 +51,44 @@ describe('AlfrescoOfficeExtensionService', () => {
|
|||||||
providers: [provideMockStore({ initialState })]
|
providers: [provideMockStore({ initialState })]
|
||||||
});
|
});
|
||||||
|
|
||||||
service = TestBed.inject(AlfrescoOfficeExtensionService);
|
onLoad$ = new Subject();
|
||||||
|
|
||||||
appConfig = TestBed.inject(AppConfigService);
|
appConfig = TestBed.inject(AppConfigService);
|
||||||
appConfig.config = Object.assign(appConfig.config, {
|
appConfig.onLoad = onLoad$;
|
||||||
aosPlugin: true
|
appConfig.config.aosPlugin = true;
|
||||||
});
|
|
||||||
|
service = TestBed.inject(AlfrescoOfficeExtensionService);
|
||||||
|
|
||||||
Object.defineProperty(window, 'localStorage', { value: mock() });
|
Object.defineProperty(window, 'localStorage', { value: mock() });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should enable plugin on load', () => {
|
||||||
|
spyOn(localStorage, 'getItem').and.returnValue(null);
|
||||||
|
spyOn(localStorage, 'setItem');
|
||||||
|
|
||||||
|
onLoad$.next({
|
||||||
|
plugins: {
|
||||||
|
aosPlugin: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
TestBed.inject(AlfrescoOfficeExtensionService);
|
||||||
|
expect(localStorage.setItem).toHaveBeenCalledWith('aosPlugin', 'true');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should disable plugin on load', () => {
|
||||||
|
spyOn(localStorage, 'removeItem');
|
||||||
|
|
||||||
|
onLoad$.next({
|
||||||
|
plugins: {
|
||||||
|
aosPlugin: false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
TestBed.inject(AlfrescoOfficeExtensionService);
|
||||||
|
expect(localStorage.removeItem).toHaveBeenCalledWith('aosPlugin');
|
||||||
|
});
|
||||||
|
|
||||||
it('Should initialize the localStorage with the item aosPlugin true if not present', () => {
|
it('Should initialize the localStorage with the item aosPlugin true if not present', () => {
|
||||||
expect(localStorage.getItem('aosPlugin')).toBeNull('The localStorage aosPlugin is not null');
|
expect(localStorage.getItem('aosPlugin')).toBeNull('The localStorage aosPlugin is not null');
|
||||||
service.enablePlugin();
|
service.enablePlugin();
|
||||||
|
@ -39,15 +39,20 @@ import {
|
|||||||
ExtensionConfig,
|
ExtensionConfig,
|
||||||
NavBarGroupRef
|
NavBarGroupRef
|
||||||
} from '@alfresco/adf-extensions';
|
} from '@alfresco/adf-extensions';
|
||||||
import { AppConfigService } from '@alfresco/adf-core';
|
import { AppConfigService, LogService } from '@alfresco/adf-core';
|
||||||
import { provideMockStore } from '@ngrx/store/testing';
|
import { provideMockStore } from '@ngrx/store/testing';
|
||||||
import { hasQuickShareEnabled } from '@alfresco/aca-shared/rules';
|
import { hasQuickShareEnabled } from '@alfresco/aca-shared/rules';
|
||||||
|
import { MatIconRegistry } from '@angular/material/icon';
|
||||||
|
import { DomSanitizer } from '@angular/platform-browser';
|
||||||
|
|
||||||
describe('AppExtensionService', () => {
|
describe('AppExtensionService', () => {
|
||||||
let service: AppExtensionService;
|
let service: AppExtensionService;
|
||||||
let store: Store<AppStore>;
|
let store: Store<AppStore>;
|
||||||
let extensions: ExtensionService;
|
let extensions: ExtensionService;
|
||||||
let appConfigService: AppConfigService;
|
let appConfigService: AppConfigService;
|
||||||
|
let logService: LogService;
|
||||||
|
let iconRegistry: MatIconRegistry;
|
||||||
|
let sanitizer: DomSanitizer;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
@ -55,6 +60,8 @@ describe('AppExtensionService', () => {
|
|||||||
providers: [provideMockStore({ initialState })]
|
providers: [provideMockStore({ initialState })]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
iconRegistry = TestBed.inject(MatIconRegistry);
|
||||||
|
sanitizer = TestBed.inject(DomSanitizer);
|
||||||
appConfigService = TestBed.inject(AppConfigService);
|
appConfigService = TestBed.inject(AppConfigService);
|
||||||
store = TestBed.inject(Store);
|
store = TestBed.inject(Store);
|
||||||
|
|
||||||
@ -62,6 +69,7 @@ describe('AppExtensionService', () => {
|
|||||||
service.repository.status.isQuickShareEnabled = true;
|
service.repository.status.isQuickShareEnabled = true;
|
||||||
|
|
||||||
extensions = TestBed.inject(ExtensionService);
|
extensions = TestBed.inject(ExtensionService);
|
||||||
|
logService = TestBed.inject(LogService);
|
||||||
});
|
});
|
||||||
|
|
||||||
const applyConfig = (config: ExtensionConfig, selection?: boolean) => {
|
const applyConfig = (config: ExtensionConfig, selection?: boolean) => {
|
||||||
@ -78,6 +86,40 @@ describe('AppExtensionService', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
describe('configs', () => {
|
describe('configs', () => {
|
||||||
|
it('should log an error during setup', async () => {
|
||||||
|
spyOn(extensions, 'load').and.returnValue(Promise.resolve(null));
|
||||||
|
spyOn(logService, 'error').and.stub();
|
||||||
|
|
||||||
|
await service.load();
|
||||||
|
expect(service.config).toBeNull();
|
||||||
|
expect(logService.error).toHaveBeenCalledWith('Extension configuration not found');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should load content metadata presets', () => {
|
||||||
|
applyConfig({
|
||||||
|
$id: 'test',
|
||||||
|
$name: 'test',
|
||||||
|
$version: '1.0.0',
|
||||||
|
$license: 'MIT',
|
||||||
|
$vendor: 'Good company',
|
||||||
|
$runtime: '1.5.0',
|
||||||
|
features: {
|
||||||
|
'content-metadata-presets': [
|
||||||
|
{
|
||||||
|
id: 'app.content.metadata.kitten-images',
|
||||||
|
'kitten-images': {
|
||||||
|
id: 'app.content.metadata.kittenAspect',
|
||||||
|
'custom:aspect': '*',
|
||||||
|
'exif:exif': ['exif:pixelXDimension', 'exif:pixelYDimension']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(service.contentMetadata).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
it('should merge two arrays based on [id] keys', () => {
|
it('should merge two arrays based on [id] keys', () => {
|
||||||
const left = [
|
const left = [
|
||||||
{
|
{
|
||||||
@ -1074,6 +1116,107 @@ describe('AppExtensionService', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('rules', () => {
|
||||||
|
it('should evaluate rule', () => {
|
||||||
|
extensions.setEvaluators({
|
||||||
|
rule1: () => true
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(service.evaluateRule('rule1')).toBeTrue();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not evaluate missing rule and return [false] by default', () => {
|
||||||
|
expect(service.evaluateRule('missing')).toBeFalse();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should confirm the rule is defined', () => {
|
||||||
|
extensions.setEvaluators({
|
||||||
|
rule1: () => true
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(service.isRuleDefined('rule1')).toBeTrue();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not confirm the rule is defined', () => {
|
||||||
|
expect(service.isRuleDefined(null)).toBeFalse();
|
||||||
|
expect(service.isRuleDefined('')).toBeFalse();
|
||||||
|
expect(service.isRuleDefined('missing')).toBeFalse();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should allow node preview', () => {
|
||||||
|
extensions.setEvaluators({
|
||||||
|
'app.canPreview': () => true
|
||||||
|
});
|
||||||
|
|
||||||
|
service.viewerRules.canPreview = 'app.canPreview';
|
||||||
|
expect(service.canPreviewNode(null)).toBeTrue();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should allow node preview with no rules', () => {
|
||||||
|
service.viewerRules = {};
|
||||||
|
expect(service.canPreviewNode(null)).toBeTrue();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not allow node preview', () => {
|
||||||
|
extensions.setEvaluators({
|
||||||
|
'app.canPreview': () => false
|
||||||
|
});
|
||||||
|
|
||||||
|
service.viewerRules.canPreview = 'app.canPreview';
|
||||||
|
expect(service.canPreviewNode(null)).toBeFalse();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should allow viewer navigation', () => {
|
||||||
|
extensions.setEvaluators({
|
||||||
|
'app.allowNavigation': () => true
|
||||||
|
});
|
||||||
|
|
||||||
|
service.viewerRules.showNavigation = 'app.allowNavigation';
|
||||||
|
expect(service.canShowViewerNavigation(null)).toBeTrue();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should allow viewer navigation with no rules', () => {
|
||||||
|
service.viewerRules.showNavigation = null;
|
||||||
|
expect(service.canShowViewerNavigation(null)).toBeTrue();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not allow viewer navigation', () => {
|
||||||
|
extensions.setEvaluators({
|
||||||
|
'app.allowNavigation': () => false
|
||||||
|
});
|
||||||
|
|
||||||
|
service.viewerRules.showNavigation = 'app.allowNavigation';
|
||||||
|
expect(service.canShowViewerNavigation(null)).toBeFalse();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should confirm the viewer extension is disabled explicitly', () => {
|
||||||
|
const extension = {
|
||||||
|
disabled: true
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(service.isViewerExtensionDisabled(extension)).toBeTrue();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should confirm the viewer extension is disabled via rules', () => {
|
||||||
|
extensions.setEvaluators({
|
||||||
|
'viewer.disabled': () => true
|
||||||
|
});
|
||||||
|
|
||||||
|
const extension = {
|
||||||
|
disabled: false,
|
||||||
|
rules: {
|
||||||
|
disabled: 'viewer.disabled'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(service.isViewerExtensionDisabled(extension)).toBeTrue();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should confirm viewer extension is not disabled by default', () => {
|
||||||
|
expect(service.isViewerExtensionDisabled({})).toBeFalse();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('rule disable', () => {
|
describe('rule disable', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
extensions.setEvaluators({
|
extensions.setEvaluators({
|
||||||
@ -1425,4 +1568,107 @@ describe('AppExtensionService', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('custom icons', () => {
|
||||||
|
it('should register custom icons', () => {
|
||||||
|
spyOn(iconRegistry, 'addSvgIconInNamespace').and.stub();
|
||||||
|
|
||||||
|
const rawUrl = './assets/images/ft_ic_ms_excel.svg';
|
||||||
|
|
||||||
|
applyConfig({
|
||||||
|
$id: 'test',
|
||||||
|
$name: 'test',
|
||||||
|
$version: '1.0.0',
|
||||||
|
$license: 'MIT',
|
||||||
|
$vendor: 'Good company',
|
||||||
|
$runtime: '1.5.0',
|
||||||
|
features: {
|
||||||
|
icons: [
|
||||||
|
{
|
||||||
|
id: 'adf:excel_thumbnail',
|
||||||
|
value: rawUrl
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const url = sanitizer.bypassSecurityTrustResourceUrl(rawUrl);
|
||||||
|
expect(iconRegistry.addSvgIconInNamespace).toHaveBeenCalledWith('adf', 'excel_thumbnail', url);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should warn if icon has no url path', () => {
|
||||||
|
const warn = spyOn(logService, 'warn').and.stub();
|
||||||
|
|
||||||
|
applyConfig({
|
||||||
|
$id: 'test',
|
||||||
|
$name: 'test',
|
||||||
|
$version: '1.0.0',
|
||||||
|
$license: 'MIT',
|
||||||
|
$vendor: 'Good company',
|
||||||
|
$runtime: '1.5.0',
|
||||||
|
features: {
|
||||||
|
icons: [
|
||||||
|
{
|
||||||
|
id: 'adf:excel_thumbnail'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(warn).toHaveBeenCalledWith('Missing icon value for "adf:excel_thumbnail".');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should warn if icon has incorrect format', () => {
|
||||||
|
const warn = spyOn(logService, 'warn').and.stub();
|
||||||
|
|
||||||
|
applyConfig({
|
||||||
|
$id: 'test',
|
||||||
|
$name: 'test',
|
||||||
|
$version: '1.0.0',
|
||||||
|
$license: 'MIT',
|
||||||
|
$vendor: 'Good company',
|
||||||
|
$runtime: '1.5.0',
|
||||||
|
features: {
|
||||||
|
icons: [
|
||||||
|
{
|
||||||
|
id: 'incorrect.format',
|
||||||
|
value: './assets/images/ft_ic_ms_excel.svg'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(warn).toHaveBeenCalledWith(`Incorrect icon id format.`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should resolve main action', (done) => {
|
||||||
|
extensions.setEvaluators({
|
||||||
|
'action.enabled': () => true
|
||||||
|
});
|
||||||
|
|
||||||
|
applyConfig({
|
||||||
|
$id: 'test',
|
||||||
|
$name: 'test',
|
||||||
|
$version: '1.0.0',
|
||||||
|
$license: 'MIT',
|
||||||
|
$vendor: 'Good company',
|
||||||
|
$runtime: '1.5.0',
|
||||||
|
features: {
|
||||||
|
mainAction: {
|
||||||
|
id: 'action-id',
|
||||||
|
title: 'action-title',
|
||||||
|
type: 'button',
|
||||||
|
rules: {
|
||||||
|
visible: 'action.enabled'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
service.getMainAction().subscribe((action) => {
|
||||||
|
expect(action.id).toEqual('action-id');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -196,9 +196,9 @@ export class AppExtensionService implements RuleContext {
|
|||||||
const value = icon.value;
|
const value = icon.value;
|
||||||
|
|
||||||
if (!value) {
|
if (!value) {
|
||||||
console.warn(`Missing icon value for "${icon.id}".`);
|
this.logger.warn(`Missing icon value for "${icon.id}".`);
|
||||||
} else if (!ns || !id) {
|
} else if (!ns || !id) {
|
||||||
console.warn(`Incorrect icon id format: "${icon.id}".`);
|
this.logger.warn(`Incorrect icon id format.`);
|
||||||
} else {
|
} else {
|
||||||
this.matIconRegistry.addSvgIconInNamespace(ns, id, this.sanitizer.bypassSecurityTrustResourceUrl(value));
|
this.matIconRegistry.addSvgIconInNamespace(ns, id, this.sanitizer.bypassSecurityTrustResourceUrl(value));
|
||||||
}
|
}
|
||||||
@ -290,12 +290,10 @@ export class AppExtensionService implements RuleContext {
|
|||||||
let presets = {};
|
let presets = {};
|
||||||
presets = this.filterDisabled(mergeObjects(presets, ...elements));
|
presets = this.filterDisabled(mergeObjects(presets, ...elements));
|
||||||
|
|
||||||
try {
|
const metadata = this.appConfig.config['content-metadata'] || {};
|
||||||
this.appConfig.config['content-metadata'].presets = presets;
|
metadata.presets = presets;
|
||||||
} catch (error) {
|
|
||||||
this.logger.error(error, '- could not change content-metadata presets from app.config -');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
this.appConfig.config['content-metadata'] = metadata;
|
||||||
return { presets };
|
return { presets };
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -310,11 +308,7 @@ export class AppExtensionService implements RuleContext {
|
|||||||
.filter((entry) => this.filterVisible(entry))
|
.filter((entry) => this.filterVisible(entry))
|
||||||
.sort(sortByOrder);
|
.sort(sortByOrder);
|
||||||
|
|
||||||
try {
|
this.appConfig.config['search'] = search;
|
||||||
this.appConfig.config['search'] = search;
|
|
||||||
} catch (error) {
|
|
||||||
this.logger.error(error, '- could not change search from app.config -');
|
|
||||||
}
|
|
||||||
return search;
|
return search;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,60 +30,49 @@ import {
|
|||||||
AppConfigService,
|
AppConfigService,
|
||||||
AlfrescoApiService,
|
AlfrescoApiService,
|
||||||
PageTitleService,
|
PageTitleService,
|
||||||
UserPreferencesService,
|
|
||||||
AlfrescoApiServiceMock,
|
AlfrescoApiServiceMock,
|
||||||
TranslationMock,
|
TranslationMock,
|
||||||
TranslationService
|
TranslationService
|
||||||
} from '@alfresco/adf-core';
|
} from '@alfresco/adf-core';
|
||||||
import { BehaviorSubject, Observable, of, Subject } from 'rxjs';
|
import { BehaviorSubject, Observable, of, Subject } from 'rxjs';
|
||||||
import { HttpClientModule } from '@angular/common/http';
|
import { HttpClientModule } from '@angular/common/http';
|
||||||
import { SharedLinksApiService, GroupService, SearchQueryBuilderService, UploadService, DiscoveryApiService } from '@alfresco/adf-content-services';
|
import {
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
DiscoveryApiService,
|
||||||
import { ContentApiService } from './content-api.service';
|
FileUploadErrorEvent,
|
||||||
import { RouterExtensionService } from './router.extension.service';
|
GroupService,
|
||||||
import { OverlayContainer } from '@angular/cdk/overlay';
|
SearchQueryBuilderService,
|
||||||
import { AppStore, STORE_INITIAL_APP_DATA } from '../../../store/src/states/app.state';
|
SharedLinksApiService,
|
||||||
import { MockStore, provideMockStore } from '@ngrx/store/testing';
|
UploadService
|
||||||
|
} from '@alfresco/adf-content-services';
|
||||||
|
import { ActivatedRoute } from '@angular/router';
|
||||||
|
import { STORE_INITIAL_APP_DATA } from '../../../store/src/states/app.state';
|
||||||
|
import { provideMockStore } from '@ngrx/store/testing';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
|
||||||
import { TranslateServiceMock } from '../testing/translation.service';
|
|
||||||
import { RouterTestingModule } from '@angular/router/testing';
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
import { RepositoryInfo } from '@alfresco/js-api';
|
import { RepositoryInfo } from '@alfresco/js-api';
|
||||||
import { AcaMobileAppSwitcherService } from './aca-mobile-app-switcher.service';
|
|
||||||
import { MatDialogModule } from '@angular/material/dialog';
|
import { MatDialogModule } from '@angular/material/dialog';
|
||||||
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
import { Store } from '@ngrx/store';
|
||||||
|
import { SnackbarErrorAction } from '../../../store/src/actions/snackbar.actions';
|
||||||
|
import { ContentApiService } from './content-api.service';
|
||||||
|
import { SetRepositoryInfoAction, SetUserProfileAction } from '../../../store/src/actions/app.actions';
|
||||||
|
|
||||||
describe('AppService', () => {
|
describe('AppService', () => {
|
||||||
let service: AppService;
|
let service: AppService;
|
||||||
let auth: AuthenticationService;
|
let auth: AuthenticationService;
|
||||||
let appConfig: AppConfigService;
|
let appConfig: AppConfigService;
|
||||||
let searchQueryBuilderService: SearchQueryBuilderService;
|
let searchQueryBuilderService: SearchQueryBuilderService;
|
||||||
let userPreferencesService: UserPreferencesService;
|
|
||||||
let router: Router;
|
|
||||||
let activatedRoute: ActivatedRoute;
|
|
||||||
let routerExtensionService: RouterExtensionService;
|
|
||||||
let pageTitleService: PageTitleService;
|
|
||||||
let uploadService: UploadService;
|
let uploadService: UploadService;
|
||||||
let contentApiService: ContentApiService;
|
let store: Store;
|
||||||
let sharedLinksApiService: SharedLinksApiService;
|
let sharedLinksApiService: SharedLinksApiService;
|
||||||
let overlayContainer: OverlayContainer;
|
let contentApi: ContentApiService;
|
||||||
let alfrescoApiService: AlfrescoApiService;
|
|
||||||
let groupService: GroupService;
|
let groupService: GroupService;
|
||||||
let storeInitialAppData: any;
|
|
||||||
let store: MockStore<AppStore>;
|
|
||||||
let acaMobileAppSwitcherService: AcaMobileAppSwitcherService;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [HttpClientModule, RouterTestingModule.withRoutes([]), MatDialogModule],
|
imports: [CommonModule, HttpClientModule, TranslateModule.forRoot(), RouterTestingModule.withRoutes([]), MatDialogModule],
|
||||||
providers: [
|
providers: [
|
||||||
CommonModule,
|
|
||||||
SearchQueryBuilderService,
|
SearchQueryBuilderService,
|
||||||
UserPreferencesService,
|
|
||||||
RouterExtensionService,
|
|
||||||
UploadService,
|
|
||||||
ContentApiService,
|
|
||||||
SharedLinksApiService,
|
|
||||||
OverlayContainer,
|
|
||||||
provideMockStore({}),
|
provideMockStore({}),
|
||||||
{
|
{
|
||||||
provide: PageTitleService,
|
provide: PageTitleService,
|
||||||
@ -118,48 +107,19 @@ describe('AppService', () => {
|
|||||||
isLoggedIn: () => false
|
isLoggedIn: () => false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ provide: TranslationService, useClass: TranslationMock },
|
{ provide: TranslationService, useClass: TranslationMock }
|
||||||
{ provide: TranslateService, useClass: TranslateServiceMock }
|
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
appConfig = TestBed.inject(AppConfigService);
|
appConfig = TestBed.inject(AppConfigService);
|
||||||
searchQueryBuilderService = TestBed.inject(SearchQueryBuilderService);
|
|
||||||
userPreferencesService = TestBed.inject(UserPreferencesService);
|
|
||||||
router = TestBed.inject(Router);
|
|
||||||
activatedRoute = TestBed.inject(ActivatedRoute);
|
|
||||||
routerExtensionService = TestBed.inject(RouterExtensionService);
|
|
||||||
pageTitleService = TestBed.inject(PageTitleService);
|
|
||||||
uploadService = TestBed.inject(UploadService);
|
|
||||||
contentApiService = TestBed.inject(ContentApiService);
|
|
||||||
sharedLinksApiService = TestBed.inject(SharedLinksApiService);
|
|
||||||
overlayContainer = TestBed.inject(OverlayContainer);
|
|
||||||
alfrescoApiService = TestBed.inject(AlfrescoApiService);
|
|
||||||
groupService = TestBed.inject(GroupService);
|
|
||||||
storeInitialAppData = TestBed.inject(STORE_INITIAL_APP_DATA);
|
|
||||||
store = TestBed.inject(MockStore);
|
|
||||||
auth = TestBed.inject(AuthenticationService);
|
auth = TestBed.inject(AuthenticationService);
|
||||||
acaMobileAppSwitcherService = TestBed.inject(AcaMobileAppSwitcherService);
|
searchQueryBuilderService = TestBed.inject(SearchQueryBuilderService);
|
||||||
|
uploadService = TestBed.inject(UploadService);
|
||||||
service = new AppService(
|
store = TestBed.inject(Store);
|
||||||
userPreferencesService,
|
sharedLinksApiService = TestBed.inject(SharedLinksApiService);
|
||||||
auth,
|
contentApi = TestBed.inject(ContentApiService);
|
||||||
store,
|
groupService = TestBed.inject(GroupService);
|
||||||
router,
|
service = TestBed.inject(AppService);
|
||||||
activatedRoute,
|
|
||||||
appConfig,
|
|
||||||
pageTitleService,
|
|
||||||
alfrescoApiService,
|
|
||||||
uploadService,
|
|
||||||
routerExtensionService,
|
|
||||||
contentApiService,
|
|
||||||
sharedLinksApiService,
|
|
||||||
groupService,
|
|
||||||
overlayContainer,
|
|
||||||
storeInitialAppData,
|
|
||||||
searchQueryBuilderService,
|
|
||||||
acaMobileAppSwitcherService
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be ready if [withCredentials] mode is used', (done) => {
|
it('should be ready if [withCredentials] mode is used', (done) => {
|
||||||
@ -169,26 +129,7 @@ describe('AppService', () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const instance = new AppService(
|
const instance = TestBed.inject(AppService);
|
||||||
userPreferencesService,
|
|
||||||
auth,
|
|
||||||
store,
|
|
||||||
router,
|
|
||||||
activatedRoute,
|
|
||||||
appConfig,
|
|
||||||
pageTitleService,
|
|
||||||
alfrescoApiService,
|
|
||||||
uploadService,
|
|
||||||
routerExtensionService,
|
|
||||||
contentApiService,
|
|
||||||
sharedLinksApiService,
|
|
||||||
groupService,
|
|
||||||
overlayContainer,
|
|
||||||
storeInitialAppData,
|
|
||||||
searchQueryBuilderService,
|
|
||||||
acaMobileAppSwitcherService
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(instance.withCredentials).toBeTruthy();
|
expect(instance.withCredentials).toBeTruthy();
|
||||||
|
|
||||||
instance.ready$.subscribe(() => {
|
instance.ready$.subscribe(() => {
|
||||||
@ -204,4 +145,98 @@ describe('AppService', () => {
|
|||||||
auth.onLogin.next();
|
auth.onLogin.next();
|
||||||
await expect(isReady).toEqual(true);
|
await expect(isReady).toEqual(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should reset search to defaults upon logout', async () => {
|
||||||
|
const resetToDefaults = spyOn(searchQueryBuilderService, 'resetToDefaults');
|
||||||
|
auth.onLogout.next(true);
|
||||||
|
|
||||||
|
await expect(resetToDefaults).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should rase notification on share link error', () => {
|
||||||
|
spyOn(store, 'select').and.returnValue(of(''));
|
||||||
|
service.init();
|
||||||
|
const dispatch = spyOn(store, 'dispatch');
|
||||||
|
|
||||||
|
sharedLinksApiService.error.next({ message: 'Error Message', statusCode: 1 });
|
||||||
|
expect(dispatch).toHaveBeenCalledWith(new SnackbarErrorAction('Error Message'));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should raise notification on upload error', async () => {
|
||||||
|
spyOn(store, 'select').and.returnValue(of(''));
|
||||||
|
service.init();
|
||||||
|
const dispatch = spyOn(store, 'dispatch');
|
||||||
|
|
||||||
|
uploadService.fileUploadError.next(new FileUploadErrorEvent(null, { status: 403 }));
|
||||||
|
expect(dispatch).toHaveBeenCalledWith(new SnackbarErrorAction('APP.MESSAGES.UPLOAD.ERROR.403'));
|
||||||
|
dispatch.calls.reset();
|
||||||
|
|
||||||
|
uploadService.fileUploadError.next(new FileUploadErrorEvent(null, { status: 404 }));
|
||||||
|
expect(dispatch).toHaveBeenCalledWith(new SnackbarErrorAction('APP.MESSAGES.UPLOAD.ERROR.404'));
|
||||||
|
dispatch.calls.reset();
|
||||||
|
|
||||||
|
uploadService.fileUploadError.next(new FileUploadErrorEvent(null, { status: 409 }));
|
||||||
|
expect(dispatch).toHaveBeenCalledWith(new SnackbarErrorAction('APP.MESSAGES.UPLOAD.ERROR.CONFLICT'));
|
||||||
|
dispatch.calls.reset();
|
||||||
|
|
||||||
|
uploadService.fileUploadError.next(new FileUploadErrorEvent(null, { status: 500 }));
|
||||||
|
expect(dispatch).toHaveBeenCalledWith(new SnackbarErrorAction('APP.MESSAGES.UPLOAD.ERROR.500'));
|
||||||
|
dispatch.calls.reset();
|
||||||
|
|
||||||
|
uploadService.fileUploadError.next(new FileUploadErrorEvent(null, { status: 504 }));
|
||||||
|
expect(dispatch).toHaveBeenCalledWith(new SnackbarErrorAction('APP.MESSAGES.UPLOAD.ERROR.504'));
|
||||||
|
dispatch.calls.reset();
|
||||||
|
|
||||||
|
uploadService.fileUploadError.next(new FileUploadErrorEvent(null, { status: 403 }));
|
||||||
|
expect(dispatch).toHaveBeenCalledWith(new SnackbarErrorAction('APP.MESSAGES.UPLOAD.ERROR.403'));
|
||||||
|
dispatch.calls.reset();
|
||||||
|
|
||||||
|
uploadService.fileUploadError.next(new FileUploadErrorEvent(null, {}));
|
||||||
|
expect(dispatch).toHaveBeenCalledWith(new SnackbarErrorAction('APP.MESSAGES.UPLOAD.ERROR.GENERIC'));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should load custom css', () => {
|
||||||
|
const appendChild = spyOn(document.head, 'appendChild');
|
||||||
|
spyOn(store, 'select').and.returnValue(of('/custom.css'));
|
||||||
|
service.init();
|
||||||
|
|
||||||
|
const cssLinkElement = document.createElement('link');
|
||||||
|
cssLinkElement.setAttribute('rel', 'stylesheet');
|
||||||
|
cssLinkElement.setAttribute('type', 'text/css');
|
||||||
|
cssLinkElement.setAttribute('href', '/custom.css');
|
||||||
|
|
||||||
|
expect(appendChild).toHaveBeenCalledWith(cssLinkElement);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should load repository status on login', () => {
|
||||||
|
const repository: any = {};
|
||||||
|
spyOn(contentApi, 'getRepositoryInformation').and.returnValue(of({ entry: { repository } }));
|
||||||
|
spyOn(store, 'select').and.returnValue(of(''));
|
||||||
|
service.init();
|
||||||
|
|
||||||
|
const dispatch = spyOn(store, 'dispatch');
|
||||||
|
auth.onLogin.next(true);
|
||||||
|
|
||||||
|
expect(dispatch).toHaveBeenCalledWith(new SetRepositoryInfoAction(repository));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should load user profile on login', async () => {
|
||||||
|
const person: any = { id: 'person' };
|
||||||
|
|
||||||
|
const group: any = { entry: {} };
|
||||||
|
const groups: any[] = [group];
|
||||||
|
|
||||||
|
spyOn(contentApi, 'getRepositoryInformation').and.returnValue(of({} as any));
|
||||||
|
spyOn(groupService, 'listAllGroupMembershipsForPerson').and.returnValue(Promise.resolve(groups));
|
||||||
|
spyOn(contentApi, 'getPerson').and.returnValue(of({ entry: person }));
|
||||||
|
|
||||||
|
spyOn(store, 'select').and.returnValue(of(''));
|
||||||
|
service.init();
|
||||||
|
|
||||||
|
const dispatch = spyOn(store, 'dispatch');
|
||||||
|
auth.onLogin.next(true);
|
||||||
|
|
||||||
|
await expect(groupService.listAllGroupMembershipsForPerson).toHaveBeenCalled();
|
||||||
|
await expect(dispatch).toHaveBeenCalledWith(new SetUserProfileAction({ person, groups: [group.entry] }));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -23,13 +23,13 @@
|
|||||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Inject, Injectable, OnDestroy } from '@angular/core';
|
import { Inject, Injectable } from '@angular/core';
|
||||||
import { AuthenticationService, AppConfigService, AlfrescoApiService, PageTitleService, UserPreferencesService } from '@alfresco/adf-core';
|
import { AuthenticationService, AppConfigService, AlfrescoApiService, PageTitleService, UserPreferencesService } from '@alfresco/adf-core';
|
||||||
import { Observable, BehaviorSubject, Subject } from 'rxjs';
|
import { Observable, BehaviorSubject } from 'rxjs';
|
||||||
import { GroupService, SearchQueryBuilderService, SharedLinksApiService, UploadService, FileUploadErrorEvent } from '@alfresco/adf-content-services';
|
import { GroupService, SearchQueryBuilderService, SharedLinksApiService, UploadService, FileUploadErrorEvent } from '@alfresco/adf-content-services';
|
||||||
import { OverlayContainer } from '@angular/cdk/overlay';
|
import { OverlayContainer } from '@angular/cdk/overlay';
|
||||||
import { ActivatedRoute, ActivationEnd, NavigationStart, Router } from '@angular/router';
|
import { ActivatedRoute, ActivationEnd, NavigationStart, Router } from '@angular/router';
|
||||||
import { filter, map, takeUntil, tap } from 'rxjs/operators';
|
import { filter, map, tap } from 'rxjs/operators';
|
||||||
import {
|
import {
|
||||||
AppState,
|
AppState,
|
||||||
AppStore,
|
AppStore,
|
||||||
@ -54,7 +54,7 @@ import { AcaMobileAppSwitcherService } from './aca-mobile-app-switcher.service';
|
|||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
// After moving shell to ADF to core, AppService will implement ShellAppService
|
// After moving shell to ADF to core, AppService will implement ShellAppService
|
||||||
export class AppService implements OnDestroy {
|
export class AppService {
|
||||||
private ready: BehaviorSubject<boolean>;
|
private ready: BehaviorSubject<boolean>;
|
||||||
ready$: Observable<boolean>;
|
ready$: Observable<boolean>;
|
||||||
|
|
||||||
@ -63,8 +63,6 @@ export class AppService implements OnDestroy {
|
|||||||
hideSidenavConditions = ['/preview/'];
|
hideSidenavConditions = ['/preview/'];
|
||||||
minimizeSidenavConditions = ['search'];
|
minimizeSidenavConditions = ['search'];
|
||||||
|
|
||||||
onDestroy$ = new Subject<boolean>();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether `withCredentials` mode is enabled.
|
* Whether `withCredentials` mode is enabled.
|
||||||
* Usually means that `Kerberos` mode is used.
|
* Usually means that `Kerberos` mode is used.
|
||||||
@ -110,11 +108,6 @@ export class AppService implements OnDestroy {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
|
||||||
this.onDestroy$.next(true);
|
|
||||||
this.onDestroy$.complete();
|
|
||||||
}
|
|
||||||
|
|
||||||
init(): void {
|
init(): void {
|
||||||
this.alfrescoApiService.getInstance().on('error', (error: { status: number; response: any }) => {
|
this.alfrescoApiService.getInstance().on('error', (error: { status: number; response: any }) => {
|
||||||
if (error.status === 401 && !this.alfrescoApiService.isExcludedErrorListener(error?.response?.req?.url)) {
|
if (error.status === 401 && !this.alfrescoApiService.isExcludedErrorListener(error?.response?.req?.url)) {
|
||||||
@ -146,24 +139,21 @@ export class AppService implements OnDestroy {
|
|||||||
this.store.dispatch(new SetCurrentUrlAction(router.url));
|
this.store.dispatch(new SetCurrentUrlAction(router.url));
|
||||||
});
|
});
|
||||||
|
|
||||||
this.router.events
|
this.router.events.pipe(filter((event) => event instanceof NavigationStart)).subscribe(() => {
|
||||||
.pipe(
|
this.store.dispatch(new ResetSelectionAction());
|
||||||
filter((event) => event instanceof NavigationStart),
|
});
|
||||||
takeUntil(this.onDestroy$)
|
|
||||||
)
|
|
||||||
.subscribe(() => {
|
|
||||||
this.store.dispatch(new ResetSelectionAction());
|
|
||||||
});
|
|
||||||
|
|
||||||
this.routerExtensionService.mapExtensionRoutes();
|
this.routerExtensionService.mapExtensionRoutes();
|
||||||
|
|
||||||
this.uploadService.fileUploadError.subscribe((error) => this.onFileUploadedError(error));
|
this.uploadService.fileUploadError.subscribe((error) => this.onFileUploadedError(error));
|
||||||
|
|
||||||
this.sharedLinksApiService.error.pipe(takeUntil(this.onDestroy$)).subscribe((err: { message: string }) => {
|
this.sharedLinksApiService.error.subscribe((err: { message: string }) => {
|
||||||
this.store.dispatch(new SnackbarErrorAction(err.message));
|
if (err?.message) {
|
||||||
|
this.store.dispatch(new SnackbarErrorAction(err.message));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.ready$.pipe(takeUntil(this.onDestroy$)).subscribe((isReady) => {
|
this.ready$.subscribe((isReady) => {
|
||||||
if (isReady) {
|
if (isReady) {
|
||||||
this.loadRepositoryStatus();
|
this.loadRepositoryStatus();
|
||||||
this.loadUserProfile();
|
this.loadUserProfile();
|
||||||
@ -182,7 +172,9 @@ export class AppService implements OnDestroy {
|
|||||||
|
|
||||||
private loadRepositoryStatus() {
|
private loadRepositoryStatus() {
|
||||||
this.contentApi.getRepositoryInformation().subscribe((response: DiscoveryEntry) => {
|
this.contentApi.getRepositoryInformation().subscribe((response: DiscoveryEntry) => {
|
||||||
this.store.dispatch(new SetRepositoryInfoAction(response.entry.repository));
|
if (response?.entry?.repository) {
|
||||||
|
this.store.dispatch(new SetRepositoryInfoAction(response.entry.repository));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,7 +193,7 @@ export class AppService implements OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
loadAppSettings() {
|
loadAppSettings() {
|
||||||
let baseShareUrl = this.config.get<string>('baseShareUrl');
|
let baseShareUrl = this.config.get<string>('baseShareUrl', '');
|
||||||
if (!baseShareUrl.endsWith('/')) {
|
if (!baseShareUrl.endsWith('/')) {
|
||||||
baseShareUrl += '/';
|
baseShareUrl += '/';
|
||||||
}
|
}
|
||||||
@ -224,23 +216,23 @@ export class AppService implements OnDestroy {
|
|||||||
onFileUploadedError(error: FileUploadErrorEvent) {
|
onFileUploadedError(error: FileUploadErrorEvent) {
|
||||||
let message = 'APP.MESSAGES.UPLOAD.ERROR.GENERIC';
|
let message = 'APP.MESSAGES.UPLOAD.ERROR.GENERIC';
|
||||||
|
|
||||||
if (error.error.status === 403) {
|
if (error?.error?.status === 403) {
|
||||||
message = 'APP.MESSAGES.UPLOAD.ERROR.403';
|
message = 'APP.MESSAGES.UPLOAD.ERROR.403';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error.error.status === 404) {
|
if (error?.error?.status === 404) {
|
||||||
message = 'APP.MESSAGES.UPLOAD.ERROR.404';
|
message = 'APP.MESSAGES.UPLOAD.ERROR.404';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error.error.status === 409) {
|
if (error?.error?.status === 409) {
|
||||||
message = 'APP.MESSAGES.UPLOAD.ERROR.CONFLICT';
|
message = 'APP.MESSAGES.UPLOAD.ERROR.CONFLICT';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error.error.status === 500) {
|
if (error?.error?.status === 500) {
|
||||||
message = 'APP.MESSAGES.UPLOAD.ERROR.500';
|
message = 'APP.MESSAGES.UPLOAD.ERROR.500';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error.error.status === 504) {
|
if (error?.error?.status === 504) {
|
||||||
message = 'APP.MESSAGES.UPLOAD.ERROR.504';
|
message = 'APP.MESSAGES.UPLOAD.ERROR.504';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,61 +61,61 @@ import { map } from 'rxjs/operators';
|
|||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class ContentApiService {
|
export class ContentApiService {
|
||||||
_nodesApi: NodesApi;
|
private _nodesApi: NodesApi;
|
||||||
get nodesApi(): NodesApi {
|
get nodesApi(): NodesApi {
|
||||||
this._nodesApi = this._nodesApi ?? new NodesApi(this.api.getInstance());
|
this._nodesApi = this._nodesApi ?? new NodesApi(this.api.getInstance());
|
||||||
return this._nodesApi;
|
return this._nodesApi;
|
||||||
}
|
}
|
||||||
|
|
||||||
_trashcanApi: TrashcanApi;
|
private _trashcanApi: TrashcanApi;
|
||||||
get trashcanApi(): TrashcanApi {
|
get trashcanApi(): TrashcanApi {
|
||||||
this._trashcanApi = this._trashcanApi ?? new TrashcanApi(this.api.getInstance());
|
this._trashcanApi = this._trashcanApi ?? new TrashcanApi(this.api.getInstance());
|
||||||
return this._trashcanApi;
|
return this._trashcanApi;
|
||||||
}
|
}
|
||||||
|
|
||||||
_sharedLinksApi: SharedlinksApi;
|
private _sharedLinksApi: SharedlinksApi;
|
||||||
get sharedLinksApi(): SharedlinksApi {
|
get sharedLinksApi(): SharedlinksApi {
|
||||||
this._sharedLinksApi = this._sharedLinksApi ?? new SharedlinksApi(this.api.getInstance());
|
this._sharedLinksApi = this._sharedLinksApi ?? new SharedlinksApi(this.api.getInstance());
|
||||||
return this._sharedLinksApi;
|
return this._sharedLinksApi;
|
||||||
}
|
}
|
||||||
|
|
||||||
_discoveryApi: DiscoveryApi;
|
private _discoveryApi: DiscoveryApi;
|
||||||
get discoveryApi(): DiscoveryApi {
|
get discoveryApi(): DiscoveryApi {
|
||||||
this._discoveryApi = this._discoveryApi ?? new DiscoveryApi(this.api.getInstance());
|
this._discoveryApi = this._discoveryApi ?? new DiscoveryApi(this.api.getInstance());
|
||||||
return this._discoveryApi;
|
return this._discoveryApi;
|
||||||
}
|
}
|
||||||
|
|
||||||
_favoritesApi: FavoritesApi;
|
private _favoritesApi: FavoritesApi;
|
||||||
get favoritesApi(): FavoritesApi {
|
get favoritesApi(): FavoritesApi {
|
||||||
this._favoritesApi = this._favoritesApi ?? new FavoritesApi(this.api.getInstance());
|
this._favoritesApi = this._favoritesApi ?? new FavoritesApi(this.api.getInstance());
|
||||||
return this._favoritesApi;
|
return this._favoritesApi;
|
||||||
}
|
}
|
||||||
|
|
||||||
_contentApi: ContentApi;
|
private _contentApi: ContentApi;
|
||||||
get contentApi(): ContentApi {
|
get contentApi(): ContentApi {
|
||||||
this._contentApi = this._contentApi ?? new ContentApi(this.api.getInstance());
|
this._contentApi = this._contentApi ?? new ContentApi(this.api.getInstance());
|
||||||
return this._contentApi;
|
return this._contentApi;
|
||||||
}
|
}
|
||||||
|
|
||||||
_sitesApi: SitesApi;
|
private _sitesApi: SitesApi;
|
||||||
get sitesApi(): SitesApi {
|
get sitesApi(): SitesApi {
|
||||||
this._sitesApi = this._sitesApi ?? new SitesApi(this.api.getInstance());
|
this._sitesApi = this._sitesApi ?? new SitesApi(this.api.getInstance());
|
||||||
return this._sitesApi;
|
return this._sitesApi;
|
||||||
}
|
}
|
||||||
|
|
||||||
_searchApi: SearchApi;
|
private _searchApi: SearchApi;
|
||||||
get searchApi(): SearchApi {
|
get searchApi(): SearchApi {
|
||||||
this._searchApi = this._searchApi ?? new SearchApi(this.api.getInstance());
|
this._searchApi = this._searchApi ?? new SearchApi(this.api.getInstance());
|
||||||
return this._searchApi;
|
return this._searchApi;
|
||||||
}
|
}
|
||||||
|
|
||||||
_peopleApi: PeopleApi;
|
private _peopleApi: PeopleApi;
|
||||||
get peopleApi(): PeopleApi {
|
get peopleApi(): PeopleApi {
|
||||||
this._peopleApi = this._peopleApi ?? new PeopleApi(this.api.getInstance());
|
this._peopleApi = this._peopleApi ?? new PeopleApi(this.api.getInstance());
|
||||||
return this._peopleApi;
|
return this._peopleApi;
|
||||||
}
|
}
|
||||||
|
|
||||||
_versionsApi: VersionsApi;
|
private _versionsApi: VersionsApi;
|
||||||
get versionsApi(): VersionsApi {
|
get versionsApi(): VersionsApi {
|
||||||
this._versionsApi = this._versionsApi ?? new VersionsApi(this.api.getInstance());
|
this._versionsApi = this._versionsApi ?? new VersionsApi(this.api.getInstance());
|
||||||
return this._versionsApi;
|
return this._versionsApi;
|
||||||
|
@ -26,16 +26,21 @@
|
|||||||
import { Node } from '@alfresco/js-api';
|
import { Node } from '@alfresco/js-api';
|
||||||
|
|
||||||
export function isLocked(node: { entry: Node }): boolean {
|
export function isLocked(node: { entry: Node }): boolean {
|
||||||
const { entry } = node;
|
if (node?.entry) {
|
||||||
|
const { entry } = node;
|
||||||
|
|
||||||
return (
|
return entry.isLocked || entry.properties?.['cm:lockType'] === 'READ_ONLY_LOCK' || entry.properties?.['cm:lockType'] === 'WRITE_LOCK';
|
||||||
(entry && entry.isLocked) ||
|
} else {
|
||||||
(entry.properties && (entry.properties['cm:lockType'] === 'READ_ONLY_LOCK' || entry.properties['cm:lockType'] === 'WRITE_LOCK'))
|
return false;
|
||||||
);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isLibrary(node: { entry: Node | any }): boolean {
|
export function isLibrary(node: { entry: Node | any }): boolean {
|
||||||
const { entry } = node;
|
if (node?.entry) {
|
||||||
|
const { entry } = node;
|
||||||
|
|
||||||
return (entry.guid && entry.id && entry.preset && entry.title && entry.visibility) || entry.nodeType === 'st:site';
|
return !!(entry.guid && entry.id && entry.preset && entry.title && entry.visibility) || entry.nodeType === 'st:site';
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
115
projects/aca-shared/src/lib/utils/note.utils.spec.ts
Normal file
115
projects/aca-shared/src/lib/utils/note.utils.spec.ts
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Alfresco Example Content Application
|
||||||
|
*
|
||||||
|
* Copyright (C) 2005 - 2020 Alfresco Software Limited
|
||||||
|
*
|
||||||
|
* This file is part of the Alfresco Example Content Application.
|
||||||
|
* If the software was purchased under a paid Alfresco license, the terms of
|
||||||
|
* the paid license agreement will prevail. Otherwise, the software is
|
||||||
|
* provided under the following open source license terms:
|
||||||
|
*
|
||||||
|
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { isLibrary, isLocked } from './node.utils';
|
||||||
|
|
||||||
|
describe('NodeUtils', () => {
|
||||||
|
describe('isLocked', () => {
|
||||||
|
it('should return [false] if entry is not defined', () => {
|
||||||
|
expect(isLocked(null)).toBeFalse();
|
||||||
|
expect(isLocked({ entry: null })).toBeFalse();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return [true] if entry is locked', () => {
|
||||||
|
expect(
|
||||||
|
isLocked({
|
||||||
|
entry: {
|
||||||
|
isLocked: true
|
||||||
|
} as any
|
||||||
|
})
|
||||||
|
).toBeTrue();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return [true] for [READ_ONLY_LOCK] type', () => {
|
||||||
|
expect(
|
||||||
|
isLocked({
|
||||||
|
entry: {
|
||||||
|
isLocked: false,
|
||||||
|
properties: {
|
||||||
|
'cm:lockType': 'READ_ONLY_LOCK'
|
||||||
|
}
|
||||||
|
} as any
|
||||||
|
})
|
||||||
|
).toBeTrue();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return [true] for [WRITE_LOCK] type', () => {
|
||||||
|
expect(
|
||||||
|
isLocked({
|
||||||
|
entry: {
|
||||||
|
isLocked: false,
|
||||||
|
properties: {
|
||||||
|
'cm:lockType': 'WRITE_LOCK'
|
||||||
|
}
|
||||||
|
} as any
|
||||||
|
})
|
||||||
|
).toBeTrue();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return [false] for unknown lock type', () => {
|
||||||
|
expect(
|
||||||
|
isLocked({
|
||||||
|
entry: {
|
||||||
|
isLocked: false,
|
||||||
|
properties: {
|
||||||
|
'cm:lockType': 'UNKNOWN'
|
||||||
|
}
|
||||||
|
} as any
|
||||||
|
})
|
||||||
|
).toBeFalse();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('isLibrary', () => {
|
||||||
|
it('should return [false] if entry is not defined', () => {
|
||||||
|
expect(isLibrary(null)).toBeFalse();
|
||||||
|
expect(isLibrary({ entry: null })).toBeFalse();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should detect library by [st:site] node type', () => {
|
||||||
|
expect(
|
||||||
|
isLibrary({
|
||||||
|
entry: {
|
||||||
|
nodeType: 'st:site'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
).toBeTrue();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should detect library by common properties', () => {
|
||||||
|
expect(
|
||||||
|
isLibrary({
|
||||||
|
entry: {
|
||||||
|
guid: '<guid>',
|
||||||
|
id: '<id>',
|
||||||
|
preset: '<preset>',
|
||||||
|
title: '<title>',
|
||||||
|
visibility: '<visibility>'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
).toBeTrue();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -65,4 +65,3 @@ export * from './lib/services/alfresco-office-extension.service';
|
|||||||
export * from './lib/utils/node.utils';
|
export * from './lib/utils/node.utils';
|
||||||
export * from './lib/shared.module';
|
export * from './lib/shared.module';
|
||||||
export * from './lib/testing/lib-testing-module';
|
export * from './lib/testing/lib-testing-module';
|
||||||
export * from './lib/testing/translation.service';
|
|
||||||
|
@ -1,32 +1,15 @@
|
|||||||
// Karma configuration file, see link for more information
|
// Karma configuration file, see link for more information
|
||||||
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||||
|
const { join } = require('path');
|
||||||
|
const getBaseKarmaConfig = require('../../karma.conf');
|
||||||
|
|
||||||
module.exports = function (config) {
|
module.exports = function (config) {
|
||||||
|
const baseConfig = getBaseKarmaConfig();
|
||||||
config.set({
|
config.set({
|
||||||
basePath: '',
|
...baseConfig,
|
||||||
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
coverageReporter: {
|
||||||
plugins: [
|
...baseConfig.coverageReporter,
|
||||||
require('karma-jasmine'),
|
dir: join(__dirname, '../../coverage/aca-viewer'),
|
||||||
require('karma-chrome-launcher'),
|
|
||||||
require('karma-jasmine-html-reporter'),
|
|
||||||
require('karma-coverage-istanbul-reporter'),
|
|
||||||
require('@angular-devkit/build-angular/plugins/karma')
|
|
||||||
],
|
|
||||||
client: {
|
|
||||||
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
|
||||||
},
|
},
|
||||||
coverageIstanbulReporter: {
|
|
||||||
dir: require('path').join(__dirname, '../../coverage/aca-viewer'),
|
|
||||||
reports: ['html', 'lcovonly', 'text-summary'],
|
|
||||||
fixWebpackSourcePaths: true
|
|
||||||
},
|
|
||||||
reporters: ['progress', 'kjhtml'],
|
|
||||||
port: 9876,
|
|
||||||
colors: true,
|
|
||||||
logLevel: config.LOG_INFO,
|
|
||||||
autoWatch: true,
|
|
||||||
browsers: ['Chrome'],
|
|
||||||
singleRun: true,
|
|
||||||
restartOnFileChange: true
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
{
|
{
|
||||||
"AOS": {
|
"AOS": {
|
||||||
"ACTION_TITLE": "Edit in Microsoft Office™"
|
"ACTION_TITLE": "Edit in Microsoft Office™",
|
||||||
|
"ERRORS": {
|
||||||
|
"UNSUPPORTED_PLATFORM": "Only supported for Windows and MacOS platforms",
|
||||||
|
"ALREADY_LOCKED": "Document '{{ nodeId }}' is locked by '{{ lockOwner }}'",
|
||||||
|
"MISSING_PROTOCOL_HANDLER": "No protocol handler found for '{{ nodeName }}'"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,35 +1,15 @@
|
|||||||
// Karma configuration file, see link for more information
|
// Karma configuration file, see link for more information
|
||||||
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||||
|
const { join } = require('path');
|
||||||
|
const getBaseKarmaConfig = require('../../karma.conf');
|
||||||
|
|
||||||
module.exports = function(config) {
|
module.exports = function (config) {
|
||||||
|
const baseConfig = getBaseKarmaConfig();
|
||||||
config.set({
|
config.set({
|
||||||
basePath: '',
|
...baseConfig,
|
||||||
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
coverageReporter: {
|
||||||
plugins: [
|
...baseConfig.coverageReporter,
|
||||||
require('karma-jasmine'),
|
dir: join(__dirname, '../../coverage/aca-office-services-ext'),
|
||||||
require('karma-chrome-launcher'),
|
|
||||||
require('karma-jasmine-html-reporter'),
|
|
||||||
require('karma-coverage-istanbul-reporter'),
|
|
||||||
require('karma-mocha-reporter'),
|
|
||||||
require('@angular-devkit/build-angular/plugins/karma')
|
|
||||||
],
|
|
||||||
client: {
|
|
||||||
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
|
||||||
},
|
},
|
||||||
coverageIstanbulReporter: {
|
|
||||||
dir: require('path').join(
|
|
||||||
__dirname,
|
|
||||||
'../../coverage/adf-office-services-ext'
|
|
||||||
),
|
|
||||||
reports: ['html', 'lcovonly'],
|
|
||||||
fixWebpackSourcePaths: true
|
|
||||||
},
|
|
||||||
reporters: ['mocha', 'kjhtml'],
|
|
||||||
port: 9876,
|
|
||||||
colors: true,
|
|
||||||
logLevel: config.LOG_INFO,
|
|
||||||
autoWatch: true,
|
|
||||||
browsers: ['Chrome'],
|
|
||||||
singleRun: true
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -0,0 +1,156 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Alfresco Example Content Application
|
||||||
|
*
|
||||||
|
* Copyright (C) 2005 - 2020 Alfresco Software Limited
|
||||||
|
*
|
||||||
|
* This file is part of the Alfresco Example Content Application.
|
||||||
|
* If the software was purchased under a paid Alfresco license, the terms of
|
||||||
|
* the paid license agreement will prevail. Otherwise, the software is
|
||||||
|
* provided under the following open source license terms:
|
||||||
|
*
|
||||||
|
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
import { AosEditOnlineService } from './aos-extension.service';
|
||||||
|
import { AppConfigService, AuthenticationService, CoreModule, LogService, NotificationService } from '@alfresco/adf-core';
|
||||||
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
|
|
||||||
|
describe('AosEditOnlineService', () => {
|
||||||
|
let aosEditOnlineService: AosEditOnlineService;
|
||||||
|
let notificationService: NotificationService;
|
||||||
|
let authenticationService: AuthenticationService;
|
||||||
|
let appConfigService: AppConfigService;
|
||||||
|
let userAgent: jasmine.Spy;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [NoopAnimationsModule, TranslateModule.forRoot(), CoreModule.forRoot()],
|
||||||
|
providers: [{ provide: LogService, useValue: { error() {} } }]
|
||||||
|
});
|
||||||
|
|
||||||
|
aosEditOnlineService = TestBed.inject(AosEditOnlineService);
|
||||||
|
notificationService = TestBed.inject(NotificationService);
|
||||||
|
authenticationService = TestBed.inject(AuthenticationService);
|
||||||
|
appConfigService = TestBed.inject(AppConfigService);
|
||||||
|
|
||||||
|
spyOn(authenticationService, 'getEcmUsername').and.returnValue('user1');
|
||||||
|
spyOn(appConfigService, 'get').and.returnValue('http://localhost:3000');
|
||||||
|
userAgent = spyOnProperty(navigator, 'userAgent').and.returnValue('mac');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should raise error if file is already locked by another user', () => {
|
||||||
|
const showError = spyOn(notificationService, 'showError').and.stub();
|
||||||
|
const node: any = {
|
||||||
|
id: 'node1',
|
||||||
|
isFile: true,
|
||||||
|
isLocked: true,
|
||||||
|
properties: {
|
||||||
|
'cm:lockType': 'WRITE_LOCK',
|
||||||
|
'cm:lockOwner': { id: 'user2' }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
aosEditOnlineService.onActionEditOnlineAos(node);
|
||||||
|
expect(showError).toHaveBeenCalledWith(`AOS.ERRORS.ALREADY_LOCKED`, null, { nodeId: 'node1', lockOwner: 'user2' });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should open document if locked by the owner', () => {
|
||||||
|
const openByUrl = spyOn(aosEditOnlineService, 'openByUrl').and.stub();
|
||||||
|
|
||||||
|
const node: any = {
|
||||||
|
id: 'node1',
|
||||||
|
name: 'file.docx',
|
||||||
|
isFile: true,
|
||||||
|
isLocked: true,
|
||||||
|
properties: {
|
||||||
|
'cm:lockType': 'READ_ONLY_LOCK',
|
||||||
|
'cm:lockOwner': { id: 'user1' }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
aosEditOnlineService.onActionEditOnlineAos(node);
|
||||||
|
// eslint-disable-next-line @cspell/spellchecker
|
||||||
|
expect(openByUrl).toHaveBeenCalledWith('ms-word', 'http://localhost:3000/Company Home/_aos_nodeid/node1/file.docx');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should open document for node with 1 path segment', () => {
|
||||||
|
const openByUrl = spyOn(aosEditOnlineService, 'openByUrl').and.stub();
|
||||||
|
|
||||||
|
const node: any = {
|
||||||
|
id: 'node1',
|
||||||
|
name: 'file.docx',
|
||||||
|
isFile: true,
|
||||||
|
isLocked: false,
|
||||||
|
path: {
|
||||||
|
elements: [{ name: 'folder1' }]
|
||||||
|
},
|
||||||
|
properties: {}
|
||||||
|
};
|
||||||
|
|
||||||
|
aosEditOnlineService.onActionEditOnlineAos(node);
|
||||||
|
expect(openByUrl).toHaveBeenCalledWith('ms-word', 'http://localhost:3000/file.docx');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should open document for node with multiple path segments', () => {
|
||||||
|
const openByUrl = spyOn(aosEditOnlineService, 'openByUrl').and.stub();
|
||||||
|
|
||||||
|
const node: any = {
|
||||||
|
id: 'node1',
|
||||||
|
name: 'file.docx',
|
||||||
|
isFile: true,
|
||||||
|
isLocked: false,
|
||||||
|
path: {
|
||||||
|
elements: [{ name: 'parent' }, { name: 'child' }]
|
||||||
|
},
|
||||||
|
properties: {}
|
||||||
|
};
|
||||||
|
|
||||||
|
aosEditOnlineService.onActionEditOnlineAos(node);
|
||||||
|
expect(openByUrl).toHaveBeenCalledWith('ms-word', 'http://localhost:3000/child/_aos_nodeid/node1/file.docx');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should raise error when protocol handler is not supported', () => {
|
||||||
|
const showError = spyOn(notificationService, 'showError').and.stub();
|
||||||
|
|
||||||
|
const node: any = {
|
||||||
|
id: 'node1',
|
||||||
|
name: 'file.txt',
|
||||||
|
isFile: true,
|
||||||
|
isLocked: false,
|
||||||
|
properties: {}
|
||||||
|
};
|
||||||
|
|
||||||
|
aosEditOnlineService.onActionEditOnlineAos(node);
|
||||||
|
expect(showError).toHaveBeenCalledWith('AOS.ERRORS.MISSING_PROTOCOL_HANDLER', null, { nodeName: 'file.txt' });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should raise error for unsupported platform', () => {
|
||||||
|
const showError = spyOn(notificationService, 'showError').and.stub();
|
||||||
|
userAgent.and.returnValue('unknown');
|
||||||
|
|
||||||
|
const node: any = {
|
||||||
|
id: 'node1',
|
||||||
|
name: 'file.docx',
|
||||||
|
isFile: true,
|
||||||
|
isLocked: false,
|
||||||
|
properties: {}
|
||||||
|
};
|
||||||
|
|
||||||
|
aosEditOnlineService.onActionEditOnlineAos(node);
|
||||||
|
expect(showError).toHaveBeenCalledWith('AOS.ERRORS.UNSUPPORTED_PLATFORM');
|
||||||
|
});
|
||||||
|
});
|
@ -24,7 +24,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* cspell:disable */
|
/* cspell:disable */
|
||||||
import { AppConfigService, AuthenticationService, NotificationService } from '@alfresco/adf-core';
|
import { AppConfigService, AuthenticationService, LogService, NotificationService } from '@alfresco/adf-core';
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { MinimalNodeEntryEntity } from '@alfresco/js-api';
|
import { MinimalNodeEntryEntity } from '@alfresco/js-api';
|
||||||
import { getFileExtension, supportedExtensions } from '@alfresco/aca-shared/rules';
|
import { getFileExtension, supportedExtensions } from '@alfresco/aca-shared/rules';
|
||||||
@ -38,9 +38,10 @@ export interface IAosEditOnlineService {
|
|||||||
})
|
})
|
||||||
export class AosEditOnlineService implements IAosEditOnlineService {
|
export class AosEditOnlineService implements IAosEditOnlineService {
|
||||||
constructor(
|
constructor(
|
||||||
private alfrescoAuthenticationService: AuthenticationService,
|
private authenticationService: AuthenticationService,
|
||||||
private appConfigService: AppConfigService,
|
private appConfigService: AppConfigService,
|
||||||
private notificationService: NotificationService
|
private notificationService: NotificationService,
|
||||||
|
private logService: LogService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
onActionEditOnlineAos(node: MinimalNodeEntryEntity): void {
|
onActionEditOnlineAos(node: MinimalNodeEntryEntity): void {
|
||||||
@ -51,10 +52,10 @@ export class AosEditOnlineService implements IAosEditOnlineService {
|
|||||||
// );
|
// );
|
||||||
const checkedOut = node.properties['cm:lockType'] === 'WRITE_LOCK' || node.properties['cm:lockType'] === 'READ_ONLY_LOCK';
|
const checkedOut = node.properties['cm:lockType'] === 'WRITE_LOCK' || node.properties['cm:lockType'] === 'READ_ONLY_LOCK';
|
||||||
const lockOwner = node.properties['cm:lockOwner'];
|
const lockOwner = node.properties['cm:lockOwner'];
|
||||||
const differentLockOwner = lockOwner.id !== this.alfrescoAuthenticationService.getEcmUsername();
|
const differentLockOwner = lockOwner.id !== this.authenticationService.getEcmUsername();
|
||||||
|
|
||||||
if (checkedOut && differentLockOwner) {
|
if (checkedOut && differentLockOwner) {
|
||||||
this.onAlreadyLockedNotification(node.id, lockOwner);
|
this.onAlreadyLockedNotification(node.id, lockOwner.id);
|
||||||
} else {
|
} else {
|
||||||
this.triggerEditOnlineAos(node);
|
this.triggerEditOnlineAos(node);
|
||||||
}
|
}
|
||||||
@ -77,17 +78,21 @@ export class AosEditOnlineService implements IAosEditOnlineService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private onAlreadyLockedNotification(nodeId: string, lockOwner: string) {
|
private onAlreadyLockedNotification(nodeId: string, lockOwner: string) {
|
||||||
this.notificationService.openSnackMessage(`Document ${nodeId} locked by ${lockOwner}`, 3000);
|
this.logService.error('Document already locked by another user');
|
||||||
|
this.notificationService.showError(`AOS.ERRORS.ALREADY_LOCKED`, null, {
|
||||||
|
nodeId,
|
||||||
|
lockOwner
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private getProtocolForFileExtension(fileExtension: string) {
|
private getProtocolForFileExtension(fileExtension: string) {
|
||||||
return supportedExtensions[fileExtension];
|
return fileExtension && supportedExtensions[fileExtension];
|
||||||
}
|
}
|
||||||
|
|
||||||
private triggerEditOnlineAos(node: MinimalNodeEntryEntity): void {
|
private triggerEditOnlineAos(node: MinimalNodeEntryEntity): void {
|
||||||
const aosHost = this.appConfigService.get('aosHost');
|
const aosHost = this.appConfigService.get('aosHost');
|
||||||
let url: string;
|
let url: string;
|
||||||
const pathElements = (node.path.elements || []).map((segment) => segment.name);
|
const pathElements = (node.path?.elements || []).map((segment) => segment.name);
|
||||||
|
|
||||||
if (!pathElements.length) {
|
if (!pathElements.length) {
|
||||||
url = `${aosHost}/Company Home/_aos_nodeid/${this.getNodeId(node)}/${encodeURIComponent(node.name)}`;
|
url = `${aosHost}/Company Home/_aos_nodeid/${this.getNodeId(node)}/${encodeURIComponent(node.name)}`;
|
||||||
@ -106,23 +111,25 @@ export class AosEditOnlineService implements IAosEditOnlineService {
|
|||||||
const protocolHandler = this.getProtocolForFileExtension(fileExtension);
|
const protocolHandler = this.getProtocolForFileExtension(fileExtension);
|
||||||
|
|
||||||
if (protocolHandler === undefined) {
|
if (protocolHandler === undefined) {
|
||||||
this.notificationService.openSnackMessage(`No protocol handler found for {fileExtension}`, 3000);
|
this.logService.error('Protocol handler missing');
|
||||||
|
this.notificationService.showError(`AOS.ERRORS.MISSING_PROTOCOL_HANDLER`, null, { nodeName: node.name });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.isWindows() && !this.isMacOs()) {
|
if (!this.isWindows() && !this.isMacOs()) {
|
||||||
this.notificationService.openSnackMessage('Only supported for Windows and Mac', 3000);
|
this.logService.error('Unsupported platform');
|
||||||
|
this.notificationService.showError('AOS.ERRORS.UNSUPPORTED_PLATFORM');
|
||||||
} else {
|
} else {
|
||||||
this.aosTryToLaunchOfficeByMsProtocolHandler(protocolHandler, url);
|
this.openByUrl(protocolHandler, url);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private aosTryToLaunchOfficeByMsProtocolHandler(protocolHandler: string, url: string) {
|
openByUrl(protocolHandler: string, url: string) {
|
||||||
const protocolUrl = protocolHandler + ':ofe%7Cu%7C' + url;
|
const finalUrl = protocolHandler + ':ofe%7Cu%7C' + url;
|
||||||
|
|
||||||
const iframe = document.createElement('iframe');
|
const iframe = document.createElement('iframe');
|
||||||
iframe.style.display = 'none';
|
iframe.style.display = 'none';
|
||||||
iframe.src = protocolUrl;
|
iframe.src = finalUrl;
|
||||||
|
|
||||||
document.body.appendChild(iframe);
|
document.body.appendChild(iframe);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user