AAE-37293 core auth provider api (#11104)

This commit is contained in:
Denys Vuika
2025-08-07 12:52:44 -04:00
committed by GitHub
parent 5213621023
commit 794bc92b4a
24 changed files with 185 additions and 153 deletions

View File

@@ -18,7 +18,7 @@
import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed } from '@angular/core/testing';
import { AboutServerSettingsComponent } from './about-server-settings.component'; import { AboutServerSettingsComponent } from './about-server-settings.component';
import { AppConfigService } from '../../app-config/app-config.service'; import { AppConfigService } from '../../app-config/app-config.service';
import { AppConfigServiceMock } from '../../common'; import { provideAppConfigTesting } from '@alfresco/adf-core';
const aboutGithubDetails = { const aboutGithubDetails = {
url: 'https://github.com/componany/repository/commits/', url: 'https://github.com/componany/repository/commits/',
@@ -36,7 +36,7 @@ describe('AboutServerSettingsComponent', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
providers: [{ provide: AppConfigService, useClass: AppConfigServiceMock }] providers: [provideAppConfigTesting()]
}); });
fixture = TestBed.createComponent(AboutServerSettingsComponent); fixture = TestBed.createComponent(AboutServerSettingsComponent);
component = fixture.componentInstance; component = fixture.componentInstance;

View File

@@ -26,8 +26,7 @@ import { BasicAlfrescoAuthService } from '../basic-auth/basic-alfresco-auth.serv
import { RedirectAuthService } from '../oidc/redirect-auth.service'; import { RedirectAuthService } from '../oidc/redirect-auth.service';
import { EMPTY, of } from 'rxjs'; import { EMPTY, of } from 'rxjs';
import { MatDialogModule } from '@angular/material/dialog'; import { MatDialogModule } from '@angular/material/dialog';
import { RouterTestingModule } from '@angular/router/testing'; import { provideCoreAuthTesting } from '../../testing/';
import { NoopAuthModule } from '../../testing';
describe('AuthGuardService', () => { describe('AuthGuardService', () => {
let state: RouterStateSnapshot; let state: RouterStateSnapshot;
@@ -42,9 +41,9 @@ describe('AuthGuardService', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [MatDialogModule, RouterTestingModule, NoopAuthModule], imports: [MatDialogModule],
providers: [ providers: [
AppConfigService, provideCoreAuthTesting(),
{ provide: RedirectAuthService, useValue: { onLogin: EMPTY, onTokenReceived: of(), init: () => {} } }, { provide: RedirectAuthService, useValue: { onLogin: EMPTY, onTokenReceived: of(), init: () => {} } },
{ {
provide: OidcAuthenticationService, provide: OidcAuthenticationService,

View File

@@ -15,34 +15,25 @@
* limitations under the License. * limitations under the License.
*/ */
import { inject, ModuleWithProviders, NgModule, InjectionToken, provideAppInitializer } from '@angular/core'; import { inject, ModuleWithProviders, NgModule, InjectionToken, provideAppInitializer, EnvironmentProviders, Provider } from '@angular/core';
import { AUTH_CONFIG, OAuthModule, OAuthStorage } from 'angular-oauth2-oidc'; import { AUTH_CONFIG, OAuthStorage, provideOAuthClient } from 'angular-oauth2-oidc';
import { AuthenticationService } from '../services/authentication.service'; import { AuthenticationService } from '../services/authentication.service';
import { AuthModuleConfig, AUTH_MODULE_CONFIG } from './auth-config'; import { AuthModuleConfig, AUTH_MODULE_CONFIG } from './auth-config';
import { authConfigFactory, AuthConfigService } from './auth-config.service'; import { authConfigFactory, AuthConfigService } from './auth-config.service';
import { AuthRoutingModule } from './auth-routing.module';
import { AuthService } from './auth.service'; import { AuthService } from './auth.service';
import { RedirectAuthService } from './redirect-auth.service'; import { RedirectAuthService } from './redirect-auth.service';
import { AuthenticationConfirmationComponent } from './view/authentication-confirmation/authentication-confirmation.component'; import { HTTP_INTERCEPTORS, provideHttpClient, withInterceptorsFromDi, withXsrfConfiguration } from '@angular/common/http';
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { TokenInterceptor } from './token.interceptor'; import { TokenInterceptor } from './token.interceptor';
import { StorageService } from '../../common/services/storage.service'; import { StorageService } from '../../common/services/storage.service';
import { provideRouter } from '@angular/router';
import { AUTH_ROUTES } from './auth.routes';
import { Authentication, AuthenticationInterceptor } from '@alfresco/adf-core/auth';
export const JWT_STORAGE_SERVICE = new InjectionToken<OAuthStorage>('JWT_STORAGE_SERVICE', { export const JWT_STORAGE_SERVICE = new InjectionToken<OAuthStorage>('JWT_STORAGE_SERVICE', {
providedIn: 'root', providedIn: 'root',
factory: () => inject(StorageService) factory: () => inject(StorageService)
}); });
/**
* Create a Login Factory function
*
* @param redirectService auth redirect service
* @returns a factory function
*/
export function loginFactory(redirectService: RedirectAuthService): () => Promise<boolean> {
return () => redirectService.init();
}
/** /**
* @returns current instance of OAuthStorage * @returns current instance of OAuthStorage
*/ */
@@ -50,11 +41,20 @@ export function oauthStorageFactory(): OAuthStorage {
return inject(JWT_STORAGE_SERVICE); return inject(JWT_STORAGE_SERVICE);
} }
@NgModule({ /**
imports: [AuthRoutingModule, OAuthModule.forRoot(), AuthenticationConfirmationComponent], * Provides core authentication api
providers: [ *
* @param config Optional configuration parameters
* @returns Angular providers
*/
export function provideCoreAuth(config: AuthModuleConfig = { useHash: false }): (Provider | EnvironmentProviders)[] {
config.preventClearHashAfterLogin = config.preventClearHashAfterLogin ?? true;
return [
provideHttpClient(withInterceptorsFromDi(), withXsrfConfiguration({ cookieName: 'CSRF-TOKEN', headerName: 'X-CSRF-TOKEN' })),
provideOAuthClient(),
provideRouter(AUTH_ROUTES),
{ provide: OAuthStorage, useFactory: oauthStorageFactory }, { provide: OAuthStorage, useFactory: oauthStorageFactory },
{ provide: AuthenticationService }, AuthenticationService,
{ {
provide: AUTH_CONFIG, provide: AUTH_CONFIG,
useFactory: authConfigFactory, useFactory: authConfigFactory,
@@ -63,17 +63,22 @@ export function oauthStorageFactory(): OAuthStorage {
RedirectAuthService, RedirectAuthService,
{ provide: AuthService, useExisting: RedirectAuthService }, { provide: AuthService, useExisting: RedirectAuthService },
provideAppInitializer(() => { provideAppInitializer(() => {
const initializerFn = loginFactory(inject(RedirectAuthService)); const redirectService = inject(RedirectAuthService);
return initializerFn(); return redirectService.init();
}), }),
{ { provide: HTTP_INTERCEPTORS, useClass: TokenInterceptor, multi: true },
provide: HTTP_INTERCEPTORS, { provide: HTTP_INTERCEPTORS, useClass: AuthenticationInterceptor, multi: true },
useClass: TokenInterceptor, { provide: AUTH_MODULE_CONFIG, useValue: config },
multi: true { provide: Authentication, useClass: AuthenticationService }
} ];
] }
/** @deprecated use `provideCoreAuth()` provider api instead */
@NgModule({
providers: [...provideCoreAuth()]
}) })
export class AuthModule { export class AuthModule {
/* @deprecated use `provideCoreAuth()` provider api instead */
static forRoot(config: AuthModuleConfig = { useHash: false }): ModuleWithProviders<AuthModule> { static forRoot(config: AuthModuleConfig = { useHash: false }): ModuleWithProviders<AuthModule> {
config.preventClearHashAfterLogin = config.preventClearHashAfterLogin ?? true; config.preventClearHashAfterLogin = config.preventClearHashAfterLogin ?? true;
return { return {

View File

@@ -15,14 +15,10 @@
* limitations under the License. * limitations under the License.
*/ */
import { NgModule } from '@angular/core'; import { Routes } from '@angular/router';
import { provideRouter, Routes } from '@angular/router';
import { AuthenticationConfirmationComponent } from './view/authentication-confirmation/authentication-confirmation.component'; import { AuthenticationConfirmationComponent } from './view/authentication-confirmation/authentication-confirmation.component';
import { OidcAuthGuard } from './oidc-auth.guard'; import { OidcAuthGuard } from './oidc-auth.guard';
const routes: Routes = [{ path: 'view/authentication-confirmation', component: AuthenticationConfirmationComponent, canActivate: [OidcAuthGuard] }]; export const AUTH_ROUTES: Routes = [
{ path: 'view/authentication-confirmation', component: AuthenticationConfirmationComponent, canActivate: [OidcAuthGuard] }
@NgModule({ ];
providers: [provideRouter(routes)]
})
export class AuthRoutingModule {}

View File

@@ -15,7 +15,6 @@
* limitations under the License. * limitations under the License.
*/ */
export * from './auth-routing.module';
export * from './auth.module'; export * from './auth.module';
export * from './auth.service'; export * from './auth.service';
export * from './oidc-auth.guard'; export * from './oidc-auth.guard';

View File

@@ -20,8 +20,8 @@ import { AuthenticationService } from './authentication.service';
import { CookieService } from '../../common/services/cookie.service'; import { CookieService } from '../../common/services/cookie.service';
import { AppConfigService } from '../../app-config/app-config.service'; import { AppConfigService } from '../../app-config/app-config.service';
import { BasicAlfrescoAuthService } from '../basic-auth/basic-alfresco-auth.service'; import { BasicAlfrescoAuthService } from '../basic-auth/basic-alfresco-auth.service';
import { AuthModule } from '../oidc/auth.module'; import { provideCoreAuth } from '../oidc/auth.module';
import { HttpHeaders, provideHttpClient } from '@angular/common/http'; import { HttpHeaders } from '@angular/common/http';
import { CookieServiceMock } from '../../mock'; import { CookieServiceMock } from '../../mock';
import { AppConfigServiceMock } from '../../common'; import { AppConfigServiceMock } from '../../common';
import { OidcAuthenticationService } from '../oidc/oidc-authentication.service'; import { OidcAuthenticationService } from '../oidc/oidc-authentication.service';
@@ -44,8 +44,8 @@ describe('AuthenticationService', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [AuthModule.forRoot({ useHash: true })],
providers: [ providers: [
provideCoreAuth({ useHash: true }),
{ {
provide: CookieService, provide: CookieService,
useClass: CookieServiceMock useClass: CookieServiceMock
@@ -53,8 +53,7 @@ describe('AuthenticationService', () => {
{ {
provide: AppConfigService, provide: AppConfigService,
useClass: AppConfigServiceMock useClass: AppConfigServiceMock
}, }
provideHttpClient()
] ]
}); });

View File

@@ -20,7 +20,7 @@ import { UserAccessService } from './user-access.service';
import { JwtHelperService } from './jwt-helper.service'; import { JwtHelperService } from './jwt-helper.service';
import { AppConfigService } from '../../app-config'; import { AppConfigService } from '../../app-config';
import { HttpClientTestingModule } from '@angular/common/http/testing'; import { HttpClientTestingModule } from '@angular/common/http/testing';
import { AuthModule, JWT_STORAGE_SERVICE } from '../oidc/auth.module'; import { JWT_STORAGE_SERVICE, provideCoreAuth } from '../oidc/auth.module';
import { StorageService } from '../../common/services/storage.service'; import { StorageService } from '../../common/services/storage.service';
describe('UserAccessService', () => { describe('UserAccessService', () => {
@@ -30,8 +30,8 @@ describe('UserAccessService', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [HttpClientTestingModule, AuthModule.forRoot({ useHash: true })], imports: [HttpClientTestingModule],
providers: [{ provide: JWT_STORAGE_SERVICE, useClass: StorageService }, UserAccessService] providers: [provideCoreAuth({ useHash: true }), { provide: JWT_STORAGE_SERVICE, useClass: StorageService }]
}); });
userAccessService = TestBed.inject(UserAccessService); userAccessService = TestBed.inject(UserAccessService);
jwtHelperService = TestBed.inject(JwtHelperService); jwtHelperService = TestBed.inject(JwtHelperService);

View File

@@ -18,7 +18,7 @@
import { TestBed } from '@angular/core/testing'; import { TestBed } from '@angular/core/testing';
import { AppConfigService } from '../../app-config/app-config.service'; import { AppConfigService } from '../../app-config/app-config.service';
import { StorageService } from '../../common/services/storage.service'; import { StorageService } from '../../common/services/storage.service';
import { NoopAuthModule } from '@alfresco/adf-core'; import { provideCoreAuthTesting } from '@alfresco/adf-core';
describe('StorageService', () => { describe('StorageService', () => {
let storage: StorageService; let storage: StorageService;
@@ -29,7 +29,7 @@ describe('StorageService', () => {
describe('with local storage and prefix', () => { describe('with local storage and prefix', () => {
beforeEach(async () => { beforeEach(async () => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [NoopAuthModule] providers: [provideCoreAuthTesting()]
}); });
appConfig = TestBed.inject(AppConfigService); appConfig = TestBed.inject(AppConfigService);
storage = TestBed.inject(StorageService); storage = TestBed.inject(StorageService);
@@ -78,7 +78,7 @@ describe('StorageService', () => {
describe('without local storage and prefix', () => { describe('without local storage and prefix', () => {
beforeEach(async () => { beforeEach(async () => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [NoopAuthModule] providers: [provideCoreAuthTesting()]
}); });
appConfig = TestBed.inject(AppConfigService); appConfig = TestBed.inject(AppConfigService);
@@ -122,7 +122,7 @@ describe('StorageService', () => {
}); });
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [NoopAuthModule] providers: [provideCoreAuthTesting()]
}); });
appConfig = TestBed.inject(AppConfigService); appConfig = TestBed.inject(AppConfigService);
storage = TestBed.inject(StorageService); storage = TestBed.inject(StorageService);

View File

@@ -39,10 +39,7 @@ import { CORE_DIRECTIVES } from './directives/directive.module';
import { CORE_PIPES } from './pipes/pipe.module'; import { CORE_PIPES } from './pipes/pipe.module';
import { TranslateLoaderService } from './translation/translate-loader.service'; import { TranslateLoaderService } from './translation/translate-loader.service';
import { SEARCH_TEXT_INPUT_DIRECTIVES } from './search-text/search-text-input.module'; import { SEARCH_TEXT_INPUT_DIRECTIVES } from './search-text/search-text-input.module';
import { AuthenticationInterceptor, Authentication } from '@alfresco/adf-core/auth'; import { HttpClient } from '@angular/common/http';
import { HTTP_INTERCEPTORS, HttpClient, provideHttpClient, withXsrfConfiguration, withInterceptorsFromDi } from '@angular/common/http';
import { AuthenticationService } from './auth/services/authentication.service';
import { MAT_SNACK_BAR_DEFAULT_OPTIONS } from '@angular/material/snack-bar';
import { AppConfigPipe } from './app-config'; import { AppConfigPipe } from './app-config';
import { IconComponent } from './icon'; import { IconComponent } from './icon';
import { SortingPickerComponent } from './sorting-picker'; import { SortingPickerComponent } from './sorting-picker';
@@ -50,9 +47,19 @@ import { DynamicChipListComponent } from './dynamic-chip-list';
import { IdentityUserInfoComponent } from './identity-user-info'; import { IdentityUserInfoComponent } from './identity-user-info';
import { UnsavedChangesDialogComponent } from './dialogs'; import { UnsavedChangesDialogComponent } from './dialogs';
import { MaterialModule } from './material.module'; import { MaterialModule } from './material.module';
import { DecimalRenderMiddlewareService, FORM_FIELD_MODEL_RENDER_MIDDLEWARE } from './form';
import { provideAppConfig } from './app-config/provide-app-config'; import { provideAppConfig } from './app-config/provide-app-config';
/**
* @deprecated this module is deprecated and will be removed
* Use the following combination instead:
* ```typescript
* providers: [
* provideI18N(...),
* provideAppConfig(),
* provideCoreAuth(...)
* ]
* ```
*/
@NgModule({ @NgModule({
imports: [ imports: [
...ABOUT_DIRECTIVES, ...ABOUT_DIRECTIVES,
@@ -129,21 +136,7 @@ export class CoreModule {
}, },
defaultLanguage: 'en' defaultLanguage: 'en'
}), }),
provideAppConfig(), provideAppConfig()
provideHttpClient(withInterceptorsFromDi(), withXsrfConfiguration({ cookieName: 'CSRF-TOKEN', headerName: 'X-CSRF-TOKEN' })),
{ provide: HTTP_INTERCEPTORS, useClass: AuthenticationInterceptor, multi: true },
{ provide: Authentication, useClass: AuthenticationService },
{
provide: MAT_SNACK_BAR_DEFAULT_OPTIONS,
useValue: {
duration: 10000
}
},
{
provide: FORM_FIELD_MODEL_RENDER_MIDDLEWARE,
useClass: DecimalRenderMiddlewareService,
multi: true
}
] ]
}; };
} }

View File

@@ -20,7 +20,9 @@ import { MatDialog, MatDialogModule, MatDialogRef } from '@angular/material/dial
import { Observable, Subject } from 'rxjs'; import { Observable, Subject } from 'rxjs';
import { UnsavedChangesDialogComponent } from './unsaved-changes-dialog.component'; import { UnsavedChangesDialogComponent } from './unsaved-changes-dialog.component';
import { UnsavedChangesGuard } from './unsaved-changes.guard'; import { UnsavedChangesGuard } from './unsaved-changes.guard';
import { AuthenticationService, AuthGuardService, NoopAuthModule } from '@alfresco/adf-core'; import { AuthenticationService } from '../../auth/services/authentication.service';
import { AuthGuardService } from '../../auth/guard/auth-guard.service';
import { provideCoreAuthTesting } from '../../testing';
describe('UnsavedChangesGuard', () => { describe('UnsavedChangesGuard', () => {
let guard: UnsavedChangesGuard; let guard: UnsavedChangesGuard;
@@ -39,8 +41,9 @@ describe('UnsavedChangesGuard', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [MatDialogModule, NoopAuthModule], imports: [MatDialogModule],
providers: [ providers: [
provideCoreAuthTesting(),
{ {
provide: AuthenticationService, provide: AuthenticationService,
useValue: { useValue: {

View File

@@ -22,7 +22,7 @@ import { of, throwError } from 'rxjs';
import { AuthenticationService } from '../auth/services/authentication.service'; import { AuthenticationService } from '../auth/services/authentication.service';
import { AppConfigService } from '../app-config/app-config.service'; import { AppConfigService } from '../app-config/app-config.service';
import { LogoutDirective } from './logout.directive'; import { LogoutDirective } from './logout.directive';
import { NoopAuthModule } from '../testing/noop-auth.module'; import { provideCoreAuthTesting } from '../testing/noop-auth.module';
import { UnitTestingUtils } from '../testing/unit-testing-utils'; import { UnitTestingUtils } from '../testing/unit-testing-utils';
describe('LogoutDirective', () => { describe('LogoutDirective', () => {
@@ -45,7 +45,8 @@ describe('LogoutDirective', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [NoopAuthModule, TestComponent] imports: [TestComponent],
providers: [provideCoreAuthTesting()]
}); });
router = TestBed.inject(Router); router = TestBed.inject(Router);
authService = TestBed.inject(AuthenticationService); authService = TestBed.inject(AuthenticationService);
@@ -118,7 +119,8 @@ describe('LogoutDirective', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [NoopAuthModule, TestComponent] imports: [TestComponent],
providers: [provideCoreAuthTesting()]
}); });
router = TestBed.inject(Router); router = TestBed.inject(Router);
authService = TestBed.inject(AuthenticationService); authService = TestBed.inject(AuthenticationService);
@@ -156,7 +158,8 @@ describe('LogoutDirective', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [NoopAuthModule, TestComponent] imports: [TestComponent],
providers: [provideCoreAuthTesting()]
}); });
router = TestBed.inject(Router); router = TestBed.inject(Router);
authService = TestBed.inject(AuthenticationService); authService = TestBed.inject(AuthenticationService);

View File

@@ -29,6 +29,7 @@ import { FORM_FIELD_MODEL_RENDER_MIDDLEWARE, FormFieldModelRenderMiddleware } fr
import { ContainerModel, FormFieldModel, FormModel, TabModel } from './widgets'; import { ContainerModel, FormFieldModel, FormModel, TabModel } from './widgets';
import { HeaderWidgetComponent } from './widgets/header/header.widget'; import { HeaderWidgetComponent } from './widgets/header/header.widget';
import { FormSectionComponent } from './form-section/form-section.component'; import { FormSectionComponent } from './form-section/form-section.component';
import { DecimalRenderMiddlewareService } from './middlewares/decimal-middleware.service';
@Component({ @Component({
selector: 'adf-form-renderer', selector: 'adf-form-renderer',
@@ -39,6 +40,11 @@ import { FormSectionComponent } from './form-section/form-section.component';
provide: FormRulesManager, provide: FormRulesManager,
useFactory: formRulesManagerFactory, useFactory: formRulesManagerFactory,
deps: [Injector] deps: [Injector]
},
{
provide: FORM_FIELD_MODEL_RENDER_MIDDLEWARE,
useClass: DecimalRenderMiddlewareService,
multi: true
} }
], ],
imports: [ imports: [

View File

@@ -18,10 +18,9 @@
import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed } from '@angular/core/testing';
import { of } from 'rxjs'; import { of } from 'rxjs';
import { OidcAuthenticationService } from '../../../auth/oidc/oidc-authentication.service'; import { OidcAuthenticationService } from '../../../auth/oidc/oidc-authentication.service';
import { UnitTestingUtils } from '../../../testing/unit-testing-utils';
import { LoginDialogPanelComponent } from './login-dialog-panel.component'; import { LoginDialogPanelComponent } from './login-dialog-panel.component';
import { BasicAlfrescoAuthService } from '../../../auth/basic-auth/basic-alfresco-auth.service'; import { BasicAlfrescoAuthService } from '../../../auth/basic-auth/basic-alfresco-auth.service';
import { NoopAuthModule } from '@alfresco/adf-core'; import { provideCoreAuthTesting, UnitTestingUtils } from '../../../testing';
describe('LoginDialogPanelComponent', () => { describe('LoginDialogPanelComponent', () => {
let component: LoginDialogPanelComponent; let component: LoginDialogPanelComponent;
@@ -33,8 +32,8 @@ describe('LoginDialogPanelComponent', () => {
beforeEach(async () => { beforeEach(async () => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [NoopAuthModule, LoginDialogPanelComponent], imports: [LoginDialogPanelComponent],
providers: [{ provide: OidcAuthenticationService, useValue: {} }] providers: [provideCoreAuthTesting(), { provide: OidcAuthenticationService, useValue: {} }]
}); });
fixture = TestBed.createComponent(LoginDialogPanelComponent); fixture = TestBed.createComponent(LoginDialogPanelComponent);
basicAlfrescoAuthService = TestBed.inject(BasicAlfrescoAuthService); basicAlfrescoAuthService = TestBed.inject(BasicAlfrescoAuthService);

View File

@@ -25,13 +25,11 @@ import { AuthenticationService } from '../../../auth/services/authentication.ser
import { UserPreferencesService } from '../../../common/services/user-preferences.service'; import { UserPreferencesService } from '../../../common/services/user-preferences.service';
import { AppConfigService } from '../../../app-config/app-config.service'; import { AppConfigService } from '../../../app-config/app-config.service';
import { BasicAlfrescoAuthService } from '../../../auth/basic-auth/basic-alfresco-auth.service'; import { BasicAlfrescoAuthService } from '../../../auth/basic-auth/basic-alfresco-auth.service';
import { UnitTestingUtils } from '../../../testing/unit-testing-utils';
import { LoginSuccessEvent } from '../../models/login-success.event'; import { LoginSuccessEvent } from '../../models/login-success.event';
import { LoginErrorEvent } from '../../models/login-error.event'; import { LoginErrorEvent } from '../../models/login-error.event';
import { provideHttpClientTesting } from '@angular/common/http/testing'; import { provideHttpClientTesting } from '@angular/common/http/testing';
import { NoopAuthModule } from '../../../testing/noop-auth.module'; import { provideCoreAuthTesting, NoopTranslationService, UnitTestingUtils } from '../../../testing';
import { TranslationService } from '../../../translation/translation.service'; import { TranslationService } from '../../../translation/translation.service';
import { NoopTranslationService } from '../../../testing/noop-translate.module';
describe('LoginComponent', () => { describe('LoginComponent', () => {
let component: LoginComponent; let component: LoginComponent;
@@ -61,8 +59,9 @@ describe('LoginComponent', () => {
beforeEach(fakeAsync(() => { beforeEach(fakeAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [NoopAuthModule, LoginComponent], imports: [LoginComponent],
providers: [ providers: [
provideCoreAuthTesting(),
provideHttpClientTesting(), provideHttpClientTesting(),
{ provide: TranslationService, useClass: NoopTranslationService }, { provide: TranslationService, useClass: NoopTranslationService },
{ {

View File

@@ -15,9 +15,11 @@
* limitations under the License. * limitations under the License.
*/ */
import { LoginComponent, LoginFooterDirective, NoopAuthModule } from '@alfresco/adf-core';
import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed } from '@angular/core/testing';
import { OidcAuthenticationService } from '../../auth/oidc/oidc-authentication.service'; import { OidcAuthenticationService } from '../../auth/oidc/oidc-authentication.service';
import { LoginComponent } from '../components/login/login.component';
import { LoginFooterDirective } from './login-footer.directive';
import { provideCoreAuthTesting } from '../../testing';
describe('LoginFooterDirective', () => { describe('LoginFooterDirective', () => {
let fixture: ComponentFixture<LoginComponent>; let fixture: ComponentFixture<LoginComponent>;
@@ -26,8 +28,9 @@ describe('LoginFooterDirective', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [NoopAuthModule, LoginComponent], imports: [LoginComponent],
providers: [ providers: [
provideCoreAuthTesting(),
{ {
provide: OidcAuthenticationService, provide: OidcAuthenticationService,
useValue: {} useValue: {}

View File

@@ -15,9 +15,11 @@
* limitations under the License. * limitations under the License.
*/ */
import { LoginComponent, LoginHeaderDirective, NoopAuthModule } from '@alfresco/adf-core';
import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed } from '@angular/core/testing';
import { OidcAuthenticationService } from '../../auth/oidc/oidc-authentication.service'; import { OidcAuthenticationService } from '../../auth/oidc/oidc-authentication.service';
import { LoginComponent } from '../components/login/login.component';
import { LoginHeaderDirective } from './login-header.directive';
import { provideCoreAuthTesting } from '../../testing';
describe('LoginHeaderDirective', () => { describe('LoginHeaderDirective', () => {
let fixture: ComponentFixture<LoginComponent>; let fixture: ComponentFixture<LoginComponent>;
@@ -26,8 +28,8 @@ describe('LoginHeaderDirective', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [NoopAuthModule, LoginComponent], imports: [LoginComponent],
providers: [{ provide: OidcAuthenticationService, useValue: {} }] providers: [provideCoreAuthTesting(), { provide: OidcAuthenticationService, useValue: {} }]
}); });
fixture = TestBed.createComponent(LoginComponent); fixture = TestBed.createComponent(LoginComponent);
component = fixture.componentInstance; component = fixture.componentInstance;

View File

@@ -22,7 +22,7 @@ import { NotificationService } from '../services/notification.service';
import { StorageService } from '../../common/services/storage.service'; import { StorageService } from '../../common/services/storage.service';
import { NOTIFICATION_TYPE, NotificationModel } from '../models/notification.model'; import { NOTIFICATION_TYPE, NotificationModel } from '../models/notification.model';
import { UnitTestingUtils } from '../../testing/unit-testing-utils'; import { UnitTestingUtils } from '../../testing/unit-testing-utils';
import { NoopAuthModule } from '../../testing/noop-auth.module'; import { provideCoreAuthTesting } from '../../testing/noop-auth.module';
import { MatIconTestingModule } from '@angular/material/icon/testing'; import { MatIconTestingModule } from '@angular/material/icon/testing';
describe('Notification History Component', () => { describe('Notification History Component', () => {
@@ -41,7 +41,8 @@ describe('Notification History Component', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [NoopAuthModule, NotificationHistoryComponent, MatIconTestingModule] imports: [NotificationHistoryComponent, MatIconTestingModule],
providers: [provideCoreAuthTesting()]
}); });
fixture = TestBed.createComponent(NotificationHistoryComponent); fixture = TestBed.createComponent(NotificationHistoryComponent);
component = fixture.componentInstance; component = fixture.componentInstance;

View File

@@ -0,0 +1,46 @@
/*!
* @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 { EnvironmentProviders, inject, provideAppInitializer, Provider } from '@angular/core';
import { AppConfigService, Status } from '../app-config';
/**
* Provides testing api for application config.
*
* @param config Custom application configuration data
* @returns Angular providers
*/
export function provideAppConfigTesting(config?: any): (Provider | EnvironmentProviders)[] {
config = config ?? {
application: {
name: 'Alfresco ADF Application',
storagePrefix: 'ADF_APP'
},
ecmHost: 'http://{hostname}{:port}/ecm',
bpmHost: 'http://{hostname}{:port}/bpm',
logLevel: 'silent'
};
return [
provideAppInitializer(() => {
const service = inject(AppConfigService);
service.config = config;
service.status = Status.LOADED;
return Promise.resolve();
})
];
}

View File

@@ -1,28 +0,0 @@
/*!
* @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 { NgModule } from '@angular/core';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { CoreModule } from '../core.module';
import { NoopTranslateModule } from './noop-translate.module';
import { NoopAuthModule } from './noop-auth.module';
/** @deprecated this module is deprecated and will be removed in the future */
@NgModule({
imports: [NoopAnimationsModule, CoreModule.forRoot(), NoopTranslateModule, NoopAuthModule]
})
export class CoreTestingModule {}

View File

@@ -15,8 +15,8 @@
* limitations under the License. * limitations under the License.
*/ */
export * from './core.testing.module';
export * from './core.story.module'; export * from './core.story.module';
export * from './noop-translate.module'; export * from './noop-translate.module';
export * from './noop-auth.module'; export * from './noop-auth.module';
export * from './unit-testing-utils'; export * from './unit-testing-utils';
export * from './app-config-testing';

View File

@@ -15,17 +15,13 @@
* limitations under the License. * limitations under the License.
*/ */
import { Injectable, NgModule, inject, provideAppInitializer } from '@angular/core'; import { EnvironmentProviders, Injectable, NgModule, Provider } from '@angular/core';
import { AuthModule, JWT_STORAGE_SERVICE } from '../auth/oidc/auth.module'; import { JWT_STORAGE_SERVICE, provideCoreAuth } from '../auth/oidc/auth.module';
import { RedirectAuthService } from '../auth/oidc/redirect-auth.service'; import { RedirectAuthService } from '../auth/oidc/redirect-auth.service';
import { HttpClientTestingModule } from '@angular/common/http/testing'; import { AppConfigService, provideAppConfig } from '../app-config';
import { RouterTestingModule } from '@angular/router/testing';
import { AppConfigService, StoragePrefixFactory } from '../app-config';
import { AppConfigServiceMock, CookieService, StorageService } from '../common'; import { AppConfigServiceMock, CookieService, StorageService } from '../common';
import { CookieServiceMock } from '../mock'; import { CookieServiceMock } from '../mock';
import { EMPTY, of } from 'rxjs'; import { EMPTY, of } from 'rxjs';
import { loadAppConfig } from '../app-config/app-config.loader';
import { AdfHttpClient } from '@alfresco/adf-core/api';
@Injectable({ providedIn: 'root' }) @Injectable({ providedIn: 'root' })
export class NoopRedirectAuthService extends RedirectAuthService { export class NoopRedirectAuthService extends RedirectAuthService {
@@ -37,22 +33,31 @@ export class NoopRedirectAuthService extends RedirectAuthService {
} }
} }
@NgModule({ /**
imports: [AuthModule.forRoot({ useHash: true }), HttpClientTestingModule, RouterTestingModule], * Provides testing api for Core Auth layer
providers: [ *
* Example:
* ```typescript
* TestBed.configureTestingModule({
* providers: [provideCoreAuthTesting()]
* });
* ```
*
* @returns list of Angular providers
*/
export function provideCoreAuthTesting(): (Provider | EnvironmentProviders)[] {
return [
provideCoreAuth({ useHash: true }),
{ provide: AppConfigService, useClass: AppConfigServiceMock }, { provide: AppConfigService, useClass: AppConfigServiceMock },
{ provide: CookieService, useClass: CookieServiceMock }, { provide: CookieService, useClass: CookieServiceMock },
{ provide: RedirectAuthService, useClass: NoopRedirectAuthService }, { provide: RedirectAuthService, useClass: NoopRedirectAuthService },
provideAppInitializer(() => { provideAppConfig(),
const initializerFn = loadAppConfig(
inject(AppConfigService),
inject(StorageService),
inject(AdfHttpClient),
inject(StoragePrefixFactory)
);
return initializerFn();
}),
{ provide: JWT_STORAGE_SERVICE, useClass: StorageService } { provide: JWT_STORAGE_SERVICE, useClass: StorageService }
] ];
}
/* @deprecated use `provideCoreAuthTesting()` instead */
@NgModule({
providers: [...provideCoreAuthTesting()]
}) })
export class NoopAuthModule {} export class NoopAuthModule {}

View File

@@ -29,7 +29,7 @@ export interface ProvideI18NConfig {
defaultLanguage?: string; defaultLanguage?: string;
/** /**
* An array of assets to be used for i18n, where each asset is a tuple containing an identifier and a path. * An array of assets to be used for i18n, where each asset is a tuple containing an identifier and a path.
* Example: [['en', '/assets/i18n/en.json'], ['fr', '/assets/i18n/fr.json']] * Example: [['adf-core', 'assets/adf-core'], ['my-translations', 'assets/my-translations']]
*/ */
assets?: [string, string][]; assets?: [string, string][];
} }

View File

@@ -18,9 +18,8 @@
import { TestBed } from '@angular/core/testing'; import { TestBed } from '@angular/core/testing';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { TranslationService } from './translation.service'; import { TranslationService } from './translation.service';
import { AppConfigService } from '../app-config/app-config.service';
import { AppConfigServiceMock } from '../common/mock/app-config.service.mock';
import { of } from 'rxjs'; import { of } from 'rxjs';
import { provideAppConfigTesting } from '../testing';
describe('TranslationService', () => { describe('TranslationService', () => {
let translationService: TranslationService; let translationService: TranslationService;
@@ -60,7 +59,7 @@ describe('TranslationService', () => {
} }
}) })
], ],
providers: [TranslationService, { provide: AppConfigService, useClass: AppConfigServiceMock }] providers: [TranslationService, provideAppConfigTesting()]
}); });
translationService = TestBed.inject(TranslationService); translationService = TestBed.inject(TranslationService);

View File

@@ -23,7 +23,7 @@ import { By } from '@angular/platform-browser';
import { of } from 'rxjs'; import { of } from 'rxjs';
import { AppConfigService } from '../../../app-config'; import { AppConfigService } from '../../../app-config';
import { EventMock } from '../../../mock'; import { EventMock } from '../../../mock';
import { NoopAuthModule, UnitTestingUtils } from '../../../testing'; import { UnitTestingUtils, provideCoreAuthTesting } from '../../../testing';
import { RenderingQueueServices } from '../../services/rendering-queue.services'; import { RenderingQueueServices } from '../../services/rendering-queue.services';
import { PdfThumbListComponent } from '../pdf-viewer-thumbnails/pdf-viewer-thumbnails.component'; import { PdfThumbListComponent } from '../pdf-viewer-thumbnails/pdf-viewer-thumbnails.component';
import { PDFJS_MODULE, PDFJS_VIEWER_MODULE, PdfViewerComponent } from './pdf-viewer.component'; import { PDFJS_MODULE, PDFJS_VIEWER_MODULE, PdfViewerComponent } from './pdf-viewer.component';
@@ -106,8 +106,9 @@ describe('Test PdfViewer component', () => {
beforeEach(async () => { beforeEach(async () => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [NoopAuthModule, PdfViewerComponent], imports: [PdfViewerComponent],
providers: [ providers: [
provideCoreAuthTesting(),
{ {
provide: MatDialog, provide: MatDialog,
useValue: { useValue: {
@@ -326,7 +327,7 @@ describe('Test PdfViewer component', () => {
() => () =>
({ ({
afterClosed: () => of('') afterClosed: () => of('')
} as any) }) as any
); );
spyOn(componentUrlTestPasswordComponent.pdfViewerComponent.close, 'emit'); spyOn(componentUrlTestPasswordComponent.pdfViewerComponent.close, 'emit');
@@ -355,8 +356,9 @@ describe('Test PdfViewer - Zoom customization', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [NoopAuthModule, PdfViewerComponent], imports: [PdfViewerComponent],
providers: [ providers: [
provideCoreAuthTesting(),
{ {
provide: MatDialog, provide: MatDialog,
useValue: { useValue: {
@@ -428,8 +430,9 @@ describe('Test PdfViewer - User interaction', () => {
}); });
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [NoopAuthModule, PdfViewerComponent], imports: [PdfViewerComponent],
providers: [ providers: [
provideCoreAuthTesting(),
{ {
provide: MatDialog, provide: MatDialog,
useValue: { useValue: {