Ng17 migration (#10295)

* Migrate to NG17

* [ci:force] - fixed deps

* [ci:force] - fixed build for testing 1

* Fixed build for all the packages

* [ci:force] - fixing lint

* [ci:force] - Fixed lint

* AAE-26163 Fix infinite loop when authentication error event occured (#10272)

* AAE-26163 Logout user after 3 login attempts failed, avoiding infinite loop when an authentication error occured, like when a user machine clock is significantly out of sync

* AAE-26163 Wait to discovery document to be loaded and user not authenticated to perform a ssoLogin, logout user if login fails after 3 attempts

* AAE-26163 Fix missed id_token_hint invoking logout when a login error occured due to a clock significantly out of sync

* AAE-26163 Add fake observable to unit test

* AAE-26163 Show oauth event logs if showDebugInformation is enabled, remove auth items if access token is not valid

* AAE-26163 Improve tryLogin error message

* AAE-26163 Check if token has expired to fix case when user access the application after the token is expired and with a clock significantly out of sync

* AAE-26163 Test logout when clock is out of sync

* AAE-26163 Create a service to check if local machine time is out of sync

* AAE-26163 Update oauthErrorEvent$ and combinedOAuthErrorsStream$ to return errors

* AAE-26163 Output error within combined oauth error event subscription

* AAE-26163 Fix lint problems

* AAE-26163 Logout user when token refresh error happens for the second time, if the token is not refreshed properly after first refresh error

* AAE-26163 Logout user once an oauth error event occur due to clock out of sync

* AAE-26163 Fix retry login error message if the OAuthErrorEvent doesn t return reason

* AAE-26163 Fix the issue where the logout API call is canceled by the authorize call when login fails due to clock synchronization problems, causing an infinite loop.

* remove console.log

* AAE-26163 Fix retry login error message if the OAuthErrorEvent reason is an empty object

* Cherry picked commit from oidc and run fix lint

* [MIGRATION] - fixed build and lint

* [MIGRATION] - Added injectionContext to avoid error NG0203 for unit tests

* [MIGRATION] - Moving mocha to jest

* [MIGRATION] - Fixing failing migrated tests

* [MIGRATION] - Migrating to Jest - working but some tests fails

* Trying to fix js-api unit tests

* Removing testing lib to sync with develop

* Fixed two excluded unit tests

* Removed unused project parts

* Removed unused project parts

* Reduced tserrors on building storybook

* Fixed sonarqube errors

* Removing temporarily eslint rule from publishing

* [MIGRATION] - Fixed lint

* [MIGRATION] - Fixed type

* [MIGRATION] - Rebased

* [MIGRATION] - Readded removed action

* [MIGRATION] - Checking deps

* [MIGRATION] - updated lock

* [ACS-9052] manage versions close button is too low (#10466)

* [ci:force] - Fixed lint

* [ACS-9052] Fixed close button in version manager position

* [ACS-9052] Reverted unwanted changes

---------

Co-authored-by: VitoAlbano <vito.albano.123@gmail.com>

* [MIGRATION] - fixed storybook builds

* [MIGRATION] - Checking if now eslint is releasable

* [MIGRATION] - Changing the building executor for eslint-rules

* Readded rule for peer deps

* Fixed wrong rule

* [ACS-9075] Fixed incorrect buttons labels color (#10489)

* Update package.json

* Fix ACA pipeline

* [ACS-9084] Fixed incorrect color for notification bell icon (#10513)

* Change dialog label padding

* [AAE-26767] - Fixed lint

* [AAE-26767] - Fixed lint

* updated dependencies

* AAE-30733 Fix incorrect alignment of icons in permission list header

* [MIGRATION] - sync package-lock

* [MIGRATION] - Fixed package on core lib

* [MIGRATION] - Removed unused lock

* Fixed licence

* [MIGRATION] - sync lock file

* [MIGRATION] - fixed lint issues

* [ACS-9271][ACA] Login page input labels are cut if the input is not empty (#10637)

* AAE-31453 Override card-view-textitem readonly color

---------

Co-authored-by: Amedeo Lepore <amedeo.lepore@hyland.com>
Co-authored-by: Ehsan Rezaei <ehsan.rezaei@hyland.com>
Co-authored-by: AleksanderSklorz <115619721+AleksanderSklorz@users.noreply.github.com>
Co-authored-by: DominikIwanek <dominik.iwanek@hyland.com>
Co-authored-by: swapnil-verma-gl <92505353+swapnil-verma-gl@users.noreply.github.com>
Co-authored-by: Wojciech Duda <69160975+wojd0@users.noreply.github.com>
Co-authored-by: dominikiwanekhyland <141320833+dominikiwanekhyland@users.noreply.github.com>
This commit is contained in:
Vito Albano
2025-02-12 11:58:57 +00:00
committed by GitHub
parent 2284ede0c7
commit 5d64c7f0ed
317 changed files with 16460 additions and 15654 deletions

View File

@@ -1,4 +0,0 @@
{
"extensions": ["ts"],
"spec": ["dist/tmp/libs/js-api/test/**/*.spec.js"]
}

23
lib/js-api/jest.config.ts Normal file
View File

@@ -0,0 +1,23 @@
/* eslint-disable */
export default {
displayName: 'js-api',
preset: '../../jest.preset.js',
testEnvironment: 'jsdom',
setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],
coverageDirectory: '../../../coverage/libs/js-api',
transform: {
'^.+\\.(ts|mjs|js|html)$': [
'jest-preset-angular',
{
tsconfig: '<rootDir>/tsconfig.spec.json',
stringifyContentPathRegex: '\\.(html|svg)$'
}
]
},
transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],
snapshotSerializers: [
'jest-preset-angular/build/serializers/no-ng-attributes',
'jest-preset-angular/build/serializers/ng-snapshot',
'jest-preset-angular/build/serializers/html-comment'
]
};

View File

@@ -6,7 +6,7 @@
"prefix": "adf",
"targets": {
"build": {
"executor": "@nrwl/js:tsc",
"executor": "@nx/js:tsc",
"outputs": ["{options.outputPath}"],
"dependsOn": ["build-esm5"],
"options": {
@@ -24,7 +24,7 @@
}
},
"build-esm5": {
"executor": "@nrwl/js:tsc",
"executor": "@nx/js:tsc",
"outputs": ["{options.outputPath}"],
"dependsOn": ["build-esm2015"],
"options": {
@@ -34,7 +34,7 @@
}
},
"build-esm2015": {
"executor": "@nrwl/js:tsc",
"executor": "@nx/js:tsc",
"outputs": ["{options.outputPath}"],
"dependsOn": ["build-cjs"],
"options": {
@@ -44,7 +44,7 @@
}
},
"build-cjs": {
"executor": "@nrwl/js:tsc",
"executor": "@nx/js:tsc",
"outputs": ["{options.outputPath}"],
"options": {
"outputPath": "dist/libs/js-api",
@@ -54,7 +54,7 @@
}
},
"build-types": {
"executor": "@nrwl/js:tsc",
"executor": "@nx/js:tsc",
"outputs": ["{options.outputPath}"],
"options": {
"outputPath": "dist/libs/js-api/typings",
@@ -76,7 +76,7 @@
}
},
"lint": {
"executor": "@nrwl/linter:eslint",
"executor": "@nx/eslint:lint",
"outputs": ["{options.outputFile}"],
"options": {
"lintFilePatterns": ["lib/js-api/**/*.ts"]
@@ -105,19 +105,12 @@
"dependsOn": ["build"]
},
"test": {
"executor": "nx:run-commands",
"executor": "@nx/jest:jest",
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
"options": {
"commands": ["nx run js-api:build:test", "mocha --full-trace --config lib/js-api/.mocharc.json", "rm -fr dist/tmp/libs/js-api"],
"parallel": false
},
"configurations": {
"ci": {
"ci": true,
"codeCoverage": true
}
}
}
"jestConfig": "lib/js-api/jest.config.ts",
"passWithNoTests": true
}}
},
"tags": []
}

View File

@@ -0,0 +1,18 @@
/*!
* @license
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import 'jest-preset-angular/setup-jest';

View File

@@ -15,4 +15,5 @@
* limitations under the License.
*/
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain
export const isBrowser = (): boolean => typeof window !== 'undefined' && typeof window.document !== 'undefined';

View File

@@ -40,6 +40,11 @@ describe('Auth', () => {
nodeMock = new NodeMock(ECM_HOST);
});
afterEach(() => {
authResponseEcmMock.cleanAll();
nodeMock.cleanAll();
});
describe('With Authentication', () => {
let alfrescoJsApi: AlfrescoApi;
@@ -52,13 +57,11 @@ describe('Auth', () => {
});
describe('login', () => {
it('should return the Ticket if all is ok', (done) => {
it('should return the Ticket if all is ok', async () => {
authResponseEcmMock.get201Response();
alfrescoJsApi.login('admin', 'admin').then((data: string) => {
assert.equal(data, 'TICKET_4479f4d3bb155195879bfbb8d5206f433488a1b1');
done();
});
const data = await alfrescoJsApi.login('admin', 'admin');
assert.equal(data, 'TICKET_4479f4d3bb155195879bfbb8d5206f433488a1b1');
});
it('should return an error if wrong credential are used 403 the login fails', (done) => {
@@ -72,26 +75,22 @@ describe('Auth', () => {
});
describe('isLoggedIn', () => {
it('should return true if the api is logged in', (done) => {
it('should return true if the api is logged in', async () => {
authResponseEcmMock.get201Response();
alfrescoJsApi.login('admin', 'admin').then(() => {
assert.equal(alfrescoJsApi.isLoggedIn(), true);
done();
});
await alfrescoJsApi.login('admin', 'admin');
assert.equal(alfrescoJsApi.isLoggedIn(), true);
});
it('should return false if the api is logged out', (done) => {
it('should return false if the api is logged out', async () => {
authResponseEcmMock.get201Response();
alfrescoJsApi.login('admin', 'admin').catch(NOOP);
authResponseEcmMock.get204ResponseLogout();
alfrescoJsApi.logout().then(() => {
assert.equal(alfrescoJsApi.isLoggedIn(), false);
done();
});
await alfrescoJsApi.logout();
assert.equal(alfrescoJsApi.isLoggedIn(), false);
});
});

View File

@@ -55,7 +55,7 @@ describe('Bpm Auth test', () => {
});
describe('With Authentication', () => {
it('login should return the Ticket if all is ok', (done) => {
it('login should return the Ticket if all is ok', async () => {
authBpmMock.get200Response();
const processAuth = new ProcessAuth({
@@ -63,10 +63,8 @@ describe('Bpm Auth test', () => {
contextRootBpm: 'activiti-app'
});
processAuth.login('admin', 'admin').then((data) => {
assert.equal(data, 'Basic YWRtaW46YWRtaW4=');
done();
});
const data = await processAuth.login('admin', 'admin');
assert.equal(data, 'Basic YWRtaW46YWRtaW4=');
});
it('login password should be removed after login', (done) => {

View File

@@ -103,7 +103,7 @@ describe('Tags', () => {
});
describe('createTags', () => {
it('should return created tags', (done: Mocha.Done) => {
it('should return created tags', (done) => {
tagMock.createTags201Response();
tagsApi.createTags([new TagBody(), new TagBody()]).then((tags) => {
assert.equal(tags.length, 2);

View File

@@ -18,10 +18,7 @@
import assert from 'assert';
import { AlfrescoApi, ContentApi, Oauth2Auth } from '../src';
import { EcmAuthMock, OAuthMock } from './mockObjects';
import jsdom from 'jsdom';
const { JSDOM } = jsdom;
const globalAny: any = global;
import { jest } from '@jest/globals';
describe('Oauth2 test', () => {
let alfrescoJsApi: AlfrescoApi;
@@ -32,7 +29,8 @@ describe('Oauth2 test', () => {
const hostOauth2 = 'https://myOauthUrl:30081';
const mockStorage = {
getItem: () => {},
setItem: () => {}
setItem: () => {},
removeItem: () => {}
};
oauth2Mock = new OAuthMock(hostOauth2);
@@ -43,6 +41,31 @@ describe('Oauth2 test', () => {
});
alfrescoJsApi.storage.setStorage(mockStorage);
Object.defineProperty(window, 'location', {
writable: true,
value: {
ancestorOrigins: null,
hash: null,
host: 'dummy.com',
port: '80',
protocol: 'http:',
hostname: 'dummy.com',
href: 'http://localhost/',
origin: 'dummy.com',
pathname: null,
search: null,
assign: (url: string) => {
window.location.href = url;
},
reload: null,
replace: null
}
});
});
afterEach(() => {
authResponseMock.cleanAll();
jest.clearAllMocks();
});
describe('Discovery urls', () => {
@@ -168,8 +191,8 @@ describe('Oauth2 test', () => {
});
});
it('should refresh token when the login not use the implicitFlow ', function (done) {
this.timeout(3000);
it('should refresh token when the login not use the implicitFlow ', (done) => {
jest.spyOn(window, 'document', 'get').mockReturnValueOnce(undefined);
oauth2Mock.get200Response();
const oauth2Auth = new Oauth2Auth(
@@ -204,8 +227,8 @@ describe('Oauth2 test', () => {
oauth2Auth.login('admin', 'admin');
});
it('should not hang the app also if teh logout is missing', function (done) {
this.timeout(3000);
it('should not hang the app also if the logout is missing', (done) => {
jest.spyOn(window, 'document', 'get').mockReturnValueOnce(undefined);
oauth2Mock.get200Response();
const oauth2Auth = new Oauth2Auth(
@@ -426,7 +449,7 @@ describe('Oauth2 test', () => {
// TODO: very flaky test, fails on different machines if running slow, might relate to `this.timeout`
// eslint-disable-next-line ban/ban
xit('should extend content session after oauth token refresh', function (done) {
this.timeout(3000);
jest.setTimeout(3000);
oauth2Mock.get200Response();
authResponseMock.get200ValidTicket();
@@ -464,7 +487,7 @@ describe('Oauth2 test', () => {
});
alfrescoApi.login('admin', 'admin');
this.timeout(3000);
jest.setTimeout(3000);
alfrescoApi.refreshToken();
});
@@ -519,13 +542,7 @@ describe('Oauth2 test', () => {
});
describe('With mocked DOM', () => {
beforeEach(() => {
const dom = new JSDOM('', { url: 'https://localhost' });
globalAny.window = dom.window;
globalAny.document = dom.window.document;
});
it('a failed hash check calls the logout', () => {
it('a failed hash check calls the logout', (done) => {
const oauth2Auth = new Oauth2Auth(
{
oauth2: {
@@ -554,13 +571,8 @@ describe('Oauth2 test', () => {
// invalid hash location leads to a reject which leads to a logout
oauth2Auth.iFrameHashListener();
setTimeout(() => {
assert.equal(logoutCalled, true);
}, 500);
});
afterEach(() => {
globalAny.window = undefined;
assert.equal(logoutCalled, true);
done();
});
});
@@ -582,10 +594,10 @@ describe('Oauth2 test', () => {
},
alfrescoJsApi
);
window.location.assign('public-url');
});
it('should return true if PathMatcher.match returns true for matching url', () => {
globalAny.window = { location: { href: 'public-url' } };
oauth2Auth.config.oauth2.publicUrls = ['public-url'];
oauth2Auth.pathMatcher = {
match: () => true
@@ -595,7 +607,6 @@ describe('Oauth2 test', () => {
});
it('should return false if PathMatcher.match returns false for matching url', () => {
globalAny.window = { location: { href: 'some-public-url' } };
oauth2Auth.config.oauth2.publicUrls = ['public-url'];
oauth2Auth.pathMatcher = {
match: () => false
@@ -609,13 +620,11 @@ describe('Oauth2 test', () => {
});
it('should return false if public urls is not set as an array list', () => {
globalAny.window = { location: { href: 'public-url-string' } };
oauth2Auth.config.oauth2.publicUrls = null;
assert.equal(oauth2Auth.isPublicUrl(), false);
});
it('should not call `implicitLogin`', async () => {
globalAny.window = { location: { href: 'public-url' } };
oauth2Auth.config.oauth2.silentLogin = true;
oauth2Auth.config.oauth2.publicUrls = ['public-url'];

View File

@@ -18,9 +18,6 @@
import assert from 'assert';
import { AlfrescoApi, Oauth2Auth } from '../src';
declare let window: any;
const globalAny: any = global;
describe('Oauth2 Implicit flow test', () => {
let oauth2Auth: Oauth2Auth;
let alfrescoJsApi: AlfrescoApi;
@@ -29,6 +26,26 @@ describe('Oauth2 Implicit flow test', () => {
alfrescoJsApi = new AlfrescoApi({
hostEcm: ''
});
Object.defineProperty(window, 'location', {
writable: true,
value: {
ancestorOrigins: null,
hash: '',
host: 'dummy.com',
port: '80',
protocol: 'http:',
hostname: 'dummy.com',
href: 'http://localhost/',
origin: 'dummy.com',
pathname: null,
search: null,
assign: (url: string) => {
window.location.href = url;
},
reload: null,
replace: null
}
});
});
it('should throw an error if redirectUri is not present', (done) => {
@@ -53,16 +70,7 @@ describe('Oauth2 Implicit flow test', () => {
});
it('should redirect to login if access token is not valid', (done) => {
window = globalAny.window = {
location: {
assign: (v: any) => {
window.location.href = v;
}
}
};
globalAny.document = {
getElementById: () => ''
};
document.getElementById = () => null;
oauth2Auth = new Oauth2Auth(
{
@@ -87,16 +95,7 @@ describe('Oauth2 Implicit flow test', () => {
});
it('should not loop over redirection when redirectUri contains hash and token is not valid ', (done) => {
window = globalAny.window = {
location: {
assign: (v: any) => {
window.location.href = v;
}
}
};
globalAny.document = {
getElementById: () => ''
};
document.getElementById = () => null;
oauth2Auth = new Oauth2Auth(
{
oauth2: {
@@ -124,16 +123,7 @@ describe('Oauth2 Implicit flow test', () => {
});
it('should not redirect to login if access token is valid', (done) => {
window = globalAny.window = {
location: {
assign: (v: any) => {
window.location.href = v;
}
}
};
globalAny.document = {
getElementById: () => ''
};
document.getElementById = () => null;
oauth2Auth = new Oauth2Auth(
{
oauth2: {
@@ -152,7 +142,7 @@ describe('Oauth2 Implicit flow test', () => {
oauth2Auth.isValidToken = () => true;
oauth2Auth.on('token_issued', () => {
assert.equal(window.location.url, undefined);
assert.equal(window.location.href, 'http://localhost/');
done();
});
@@ -162,27 +152,9 @@ describe('Oauth2 Implicit flow test', () => {
});
it('should set the loginFragment to redirect after the login if it is present', (done) => {
window = globalAny.window = {
location: {
assign: (v: any) => {
window.location.href = v;
}
}
};
globalAny.document = {
getElementById: () => ''
};
window.location.hash = 'asfasfasfa';
Object.defineProperty(window.location, 'hash', {
writable: true,
value: '#/redirect-path&session_state=eqfqwfqwf'
});
Object.defineProperty(window.location, 'href', {
writable: true,
value: 'https://stoca/#/redirect-path&session_state=eqfqwfqwf'
});
document.getElementById = () => null;
window.location.hash = '#/redirect-path&session_state=eqfqwfqwf';
window.location.href = 'https://stoca/#/redirect-path&session_state=eqfqwfqwf';
oauth2Auth = new Oauth2Auth(
{

View File

@@ -61,12 +61,10 @@ describe('Upload', () => {
const file = createTestFileStream('testFile.txt');
uploadApi.uploadFile(file).catch(
(error: any) => {
assert.equal(error.status, 409);
done();
}
);
uploadApi.uploadFile(file).catch((error: any) => {
assert.equal(error.status, 409);
done();
});
});
it('upload file should get 200 and rename if the new name clashes with an existing file in the current parent folder and autorename is true', async () => {

View File

@@ -8,7 +8,7 @@
"isolatedModules": true,
"allowSyntheticDefaultImports": true,
"lib": ["ESNext", "dom"],
"types": ["mocha"]
"types": ["jest", "node"]
},
"exclude": [],
"include": ["**/*"]