diff --git a/npm/ng-packs/packages/core/src/lib/services/localization.service.ts b/npm/ng-packs/packages/core/src/lib/services/localization.service.ts
index b433a3d424..dd6def0c24 100644
--- a/npm/ng-packs/packages/core/src/lib/services/localization.service.ts
+++ b/npm/ng-packs/packages/core/src/lib/services/localization.service.ts
@@ -273,11 +273,7 @@ function recursivelyMergeBaseResources(
): ApplicationLocalizationResourceDto {
const item = source[baseResourceName];
- if (!item) {
- return { texts: {}, baseResources: [] };
- }
-
- if (!item.baseResources || item.baseResources.length === 0) {
+ if (item.baseResources.length === 0) {
return item;
}
diff --git a/npm/ng-packs/packages/core/src/lib/tests/content-projection.service.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/content-projection.service.spec.ts
index 6c0843e82a..34f9451b0a 100644
--- a/npm/ng-packs/packages/core/src/lib/tests/content-projection.service.spec.ts
+++ b/npm/ng-packs/packages/core/src/lib/tests/content-projection.service.spec.ts
@@ -4,19 +4,12 @@ import { ContentProjectionService } from '../services';
import { PROJECTION_STRATEGY } from '../strategies';
describe('ContentProjectionService', () => {
- @Component({ template: '
bar
', standalone: true })
+ @Component({ template: 'bar
' })
class TestComponent {}
- @Component({
- template: '{{ contextData }}
',
- standalone: true
- })
- class ContextComponent {
- contextData: string = '';
- }
-
+ // createServiceFactory does not accept entryComponents directly
@NgModule({
- imports: [TestComponent, ContextComponent],
+ declarations: [TestComponent],
})
class TestModule {}
@@ -29,16 +22,10 @@ describe('ContentProjectionService', () => {
beforeEach(() => (spectator = createService()));
- afterEach(() => {
- if (componentRef) {
- componentRef.destroy();
- }
- const elements = document.querySelectorAll('ng-component');
- elements.forEach(el => el.remove());
- });
+ afterEach(() => componentRef.destroy());
describe('#projectContent', () => {
- it('should call injectContent of given projectionStrategy and return what it returns for AppendComponentToBody', () => {
+ it('should call injectContent of given projectionStrategy and return what it returns', () => {
const strategy = PROJECTION_STRATEGY.AppendComponentToBody(TestComponent);
componentRef = spectator.service.projectContent(strategy);
const foo = document.querySelector('body > ng-component > div.foo');
@@ -46,43 +33,5 @@ describe('ContentProjectionService', () => {
expect(componentRef).toBeInstanceOf(ComponentRef);
expect(foo.textContent).toBe('bar');
});
-
- it('should handle component with context for AppendComponentToBody', () => {
- const strategy = PROJECTION_STRATEGY.AppendComponentToBody(
- ContextComponent,
- { contextData: 'context test' }
- );
- componentRef = spectator.service.projectContent(strategy);
-
- const contextDiv = document.querySelector('body > ng-component > div.context');
- expect(componentRef).toBeInstanceOf(ComponentRef);
- expect(contextDiv.textContent).toBe('context test');
- });
-
- it('should return ComponentRef when projecting component', () => {
- const strategy = PROJECTION_STRATEGY.AppendComponentToBody(TestComponent);
- const result = spectator.service.projectContent(strategy);
-
- expect(result).toBeInstanceOf(ComponentRef);
- expect(result.componentType).toBe(TestComponent);
- });
-
- it('should work with different projection strategies', () => {
- const appendStrategy = PROJECTION_STRATEGY.AppendComponentToBody(TestComponent);
- const appendResult = spectator.service.projectContent(appendStrategy);
-
- expect(appendResult).toBeInstanceOf(ComponentRef);
-
- appendResult.destroy();
-
- const contextStrategy = PROJECTION_STRATEGY.AppendComponentToBody(
- ContextComponent,
- { contextData: 'test context' }
- );
- const contextResult = spectator.service.projectContent(contextStrategy);
-
- expect(contextResult).toBeInstanceOf(ComponentRef);
- expect(contextResult.componentType).toBe(ContextComponent);
- });
});
});
diff --git a/npm/ng-packs/packages/core/src/lib/tests/date-utils.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/date-utils.spec.ts
index b0f16b09c8..33f02dfb4f 100644
--- a/npm/ng-packs/packages/core/src/lib/tests/date-utils.spec.ts
+++ b/npm/ng-packs/packages/core/src/lib/tests/date-utils.spec.ts
@@ -1,4 +1,3 @@
-import { TestBed } from '@angular/core/testing';
import { ConfigStateService } from '../services';
import { getShortDateFormat, getShortDateShortTimeFormat, getShortTimeFormat } from '../utils';
@@ -16,17 +15,7 @@ describe('Date Utils', () => {
let config: ConfigStateService;
beforeEach(() => {
- TestBed.configureTestingModule({
- providers: [
- {
- provide: ConfigStateService,
- useValue: {
- getDeep: jest.fn(),
- },
- },
- ],
- });
- config = TestBed.inject(ConfigStateService);
+ config = new ConfigStateService(null, null, null);
});
describe('#getShortDateFormat', () => {
@@ -47,20 +36,6 @@ describe('Date Utils', () => {
expect(getShortTimeFormat(config)).toBe('h:mm a');
expect(getDeepSpy).toHaveBeenCalledWith('localization.currentCulture.dateTimeFormat');
});
-
- test('should handle null shortTimePattern', () => {
- const getDeepSpy = jest.spyOn(config, 'getDeep');
- getDeepSpy.mockReturnValueOnce({ ...dateTimeFormat, shortTimePattern: null });
-
- expect(getShortTimeFormat(config)).toBeUndefined();
- });
-
- test('should handle undefined shortTimePattern', () => {
- const getDeepSpy = jest.spyOn(config, 'getDeep');
- getDeepSpy.mockReturnValueOnce({ ...dateTimeFormat, shortTimePattern: undefined });
-
- expect(getShortTimeFormat(config)).toBeUndefined();
- });
});
describe('#getShortDateShortTimeFormat', () => {
@@ -71,19 +46,5 @@ describe('Date Utils', () => {
expect(getShortDateShortTimeFormat(config)).toBe('M/d/yyyy h:mm a');
expect(getDeepSpy).toHaveBeenCalledWith('localization.currentCulture.dateTimeFormat');
});
-
- test('should handle null shortTimePattern', () => {
- const getDeepSpy = jest.spyOn(config, 'getDeep');
- getDeepSpy.mockReturnValueOnce({ ...dateTimeFormat, shortTimePattern: null });
-
- expect(getShortDateShortTimeFormat(config)).toBe('M/d/yyyy undefined');
- });
-
- test('should handle undefined shortTimePattern', () => {
- const getDeepSpy = jest.spyOn(config, 'getDeep');
- getDeepSpy.mockReturnValueOnce({ ...dateTimeFormat, shortTimePattern: undefined });
-
- expect(getShortDateShortTimeFormat(config)).toBe('M/d/yyyy undefined');
- });
});
});
diff --git a/npm/ng-packs/packages/core/src/lib/tests/dynamic-layout.component.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/dynamic-layout.component.spec.ts
index 5d267d61a2..aac6c41fcd 100644
--- a/npm/ng-packs/packages/core/src/lib/tests/dynamic-layout.component.spec.ts
+++ b/npm/ng-packs/packages/core/src/lib/tests/dynamic-layout.component.spec.ts
@@ -1,281 +1,201 @@
-import { HttpClient } from '@angular/common/http';
-import { Component, inject as inject_1 } from '@angular/core';
-import { ActivatedRoute, RouterModule, RouterOutlet } from '@angular/router';
-import { of, BehaviorSubject } from 'rxjs';
-import { createRoutingFactory, SpectatorRouting } from '@ngneat/spectator/jest';
-import { DynamicLayoutComponent, RouterOutletComponent } from '../components';
-import { eLayoutType } from '../enums/common';
-import { ABP } from '../models';
-import { AbpApplicationConfigurationService } from '../proxy/volo/abp/asp-net-core/mvc/application-configurations/abp-application-configuration.service';
-import { ReplaceableComponentsService, RoutesService, RouterEvents, EnvironmentService, LocalizationService } from '../services';
-import { DYNAMIC_LAYOUTS_TOKEN } from '../tokens/dynamic-layout.token';
-
-const mockRoutesService = () => ({
- add: jest.fn(),
- find: jest.fn((predicate) => {
-
- if (predicate && typeof predicate === 'function') {
- if (predicate({ path: '/parentWithLayout/childWithoutLayout' })) {
- return { layout: eLayoutType.application };
- }
- if (predicate({ path: '/parentWithLayout/childWithLayout' })) {
- return { layout: eLayoutType.account };
- }
- if (predicate({ path: '/withData' })) {
- return { layout: eLayoutType.empty };
- }
- if (predicate({ path: '/withoutLayout' })) {
- return { layout: null };
- }
- }
- return null;
- }),
- search: jest.fn((query) => {
-
- if (query && query.invisible) {
- return { layout: eLayoutType.account };
- }
- return null;
- }),
- flat$: of([]),
- tree$: of([]),
- visible$: of([]),
-});
-
-@Component({
- selector: 'abp-layout-application',
- template: '',
- standalone: true,
- imports: [RouterOutlet],
-})
-class DummyApplicationLayoutComponent {}
-
-@Component({
- selector: 'abp-layout-account',
- template: '',
- standalone: true,
- imports: [RouterOutlet],
-})
-class DummyAccountLayoutComponent {}
-
-@Component({
- selector: 'abp-layout-empty',
- template: '',
- standalone: true,
- imports: [RouterOutlet],
-})
-class DummyEmptyLayoutComponent {}
-
-const LAYOUTS = [
- DummyApplicationLayoutComponent,
- DummyAccountLayoutComponent,
- DummyEmptyLayoutComponent,
-];
-
-@Component({
- selector: 'abp-dummy',
- template: '{{route.snapshot.data?.name}} works!',
- standalone: true,
-})
-class DummyComponent {
- route = inject_1(ActivatedRoute);
-}
-
-const routes: ABP.Route[] = [
- {
- path: '',
- name: 'Root',
- },
- {
- path: '/parentWithLayout',
- name: 'ParentWithLayout',
- parentName: 'Root',
- layout: eLayoutType.application,
- },
- {
- path: '/parentWithLayout/childWithoutLayout',
- name: 'ChildWithoutLayout',
- parentName: 'ParentWithLayout',
- },
- {
- path: '/parentWithLayout/childWithLayout',
- name: 'ChildWithLayout',
- parentName: 'ParentWithLayout',
- layout: eLayoutType.account,
- },
- {
- path: '/withData',
- name: 'WithData',
- layout: eLayoutType.application,
- },
-];
-
-describe('DynamicLayoutComponent', () => {
- const createComponent = createRoutingFactory({
- component: DynamicLayoutComponent,
- stubsEnabled: false,
- declarations: [],
- mocks: [AbpApplicationConfigurationService, HttpClient],
- providers: [
- {
- provide: RoutesService,
- useValue: mockRoutesService(),
- },
- {
- provide: RouterEvents,
- useValue: {
- getNavigationEvents: jest.fn().mockReturnValue(of({})),
- },
- },
- {
- provide: EnvironmentService,
- useValue: {
- getEnvironment: jest.fn().mockReturnValue({
- oAuthConfig: { responseType: 'code' },
- }),
- },
- },
- {
- provide: LocalizationService,
- useValue: {
- languageChange$: new BehaviorSubject('en'),
- },
- },
- {
- provide: DYNAMIC_LAYOUTS_TOKEN,
- useValue: new Map([
- [eLayoutType.application, 'Theme.ApplicationLayoutComponent'],
- [eLayoutType.account, 'Theme.AccountLayoutComponent'],
- [eLayoutType.empty, 'Theme.EmptyLayoutComponent'],
- ]),
- },
- {
- provide: ReplaceableComponentsService,
- useValue: {
- add: jest.fn(),
- get: jest.fn((key) => {
- if (key === 'Theme.ApplicationLayoutComponent') {
- return { component: DummyApplicationLayoutComponent };
- }
- if (key === 'Theme.AccountLayoutComponent') {
- return { component: DummyAccountLayoutComponent };
- }
- if (key === 'Theme.EmptyLayoutComponent') {
- return { component: DummyEmptyLayoutComponent };
- }
- return null;
- }),
- },
- },
- ],
- imports: [RouterModule, DummyComponent, DynamicLayoutComponent, ...LAYOUTS],
- routes: [
- { path: '', component: RouterOutletComponent },
- {
- path: 'parentWithLayout',
- component: DynamicLayoutComponent,
- children: [
- {
- path: 'childWithoutLayout',
- component: DummyComponent,
- data: { name: 'childWithoutLayout' },
- },
- {
- path: 'childWithLayout',
- component: DummyComponent,
- data: { name: 'childWithLayout' },
- },
- ],
- },
- {
- path: 'withData',
- component: DynamicLayoutComponent,
- children: [
- {
- path: '',
- component: DummyComponent,
- data: { name: 'withData' },
- },
- ],
- data: { layout: eLayoutType.empty },
- },
- {
- path: 'withoutLayout',
- component: DynamicLayoutComponent,
- children: [
- {
- path: '',
- component: DummyComponent,
- data: { name: 'withoutLayout' },
- },
- ],
- data: { layout: null },
- },
- ],
- });
-
- let spectator: SpectatorRouting;
- let replaceableComponents: ReplaceableComponentsService;
-
- beforeEach(async () => {
- spectator = createComponent();
- replaceableComponents = spectator.inject(ReplaceableComponentsService);
- const routesService = spectator.inject(RoutesService);
- routesService.add(routes);
-
- replaceableComponents.add({
- key: 'Theme.ApplicationLayoutComponent',
- component: DummyApplicationLayoutComponent,
- });
- replaceableComponents.add({
- key: 'Theme.AccountLayoutComponent',
- component: DummyAccountLayoutComponent,
- });
- replaceableComponents.add({
- key: 'Theme.EmptyLayoutComponent',
- component: DummyEmptyLayoutComponent,
- });
- });
-
- it('should handle application layout from parent abp route and display it', async () => {
- spectator.router.navigateByUrl('/parentWithLayout/childWithoutLayout');
- await spectator.fixture.whenStable();
- await new Promise(resolve => setTimeout(resolve, 100));
- spectator.detectComponentChanges();
- expect(spectator.query('abp-dynamic-layout')).toBeTruthy();
- expect(spectator.query('abp-layout-application')).toBeTruthy();
- });
-
- it('should handle account layout from own property and display it', async () => {
- spectator.router.navigateByUrl('/parentWithLayout/childWithLayout');
- await spectator.fixture.whenStable();
- await new Promise(resolve => setTimeout(resolve, 100));
- spectator.detectComponentChanges();
- expect(spectator.query('abp-layout-account')).toBeTruthy();
- });
-
- it('should handle empty layout from route data and display it', async () => {
- spectator.router.navigateByUrl('/withData');
- await spectator.fixture.whenStable();
- await new Promise(resolve => setTimeout(resolve, 100));
- spectator.detectComponentChanges();
- expect(spectator.query('abp-layout-empty')).toBeTruthy();
- });
-
- it('should display empty layout when layout is null', async () => {
- spectator.router.navigateByUrl('/withoutLayout');
- await spectator.fixture.whenStable();
- await new Promise(resolve => setTimeout(resolve, 100));
- spectator.detectComponentChanges();
- expect(spectator.query('abp-layout-empty')).toBeTruthy();
- });
-
- it('should handle layout not found scenario', async () => {
- spectator.router.navigateByUrl('/withoutLayout');
- await spectator.fixture.whenStable();
- await new Promise(resolve => setTimeout(resolve, 100));
- spectator.detectComponentChanges();
-
- expect(spectator.query('abp-dynamic-layout')).toBeTruthy();
- });
-});
+import { HttpClient } from '@angular/common/http';
+import { Component, NgModule, inject as inject_1 } from '@angular/core';
+import { ActivatedRoute, RouterModule } from '@angular/router';
+import { createRoutingFactory, SpectatorRouting } from '@ngneat/spectator/jest';
+import { DynamicLayoutComponent, RouterOutletComponent } from '../components';
+import { eLayoutType } from '../enums/common';
+import { ABP } from '../models';
+import { AbpApplicationConfigurationService } from '../proxy/volo/abp/asp-net-core/mvc/application-configurations/abp-application-configuration.service';
+import { ReplaceableComponentsService, RoutesService } from '../services';
+import { mockRoutesService } from './routes.service.spec';
+
+@Component({
+ selector: 'abp-layout-application',
+ template: '',
+})
+class DummyApplicationLayoutComponent {}
+
+@Component({
+ selector: 'abp-layout-account',
+ template: '',
+})
+class DummyAccountLayoutComponent {}
+
+@Component({
+ selector: 'abp-layout-empty',
+ template: '',
+})
+class DummyEmptyLayoutComponent {}
+
+const LAYOUTS = [
+ DummyApplicationLayoutComponent,
+ DummyAccountLayoutComponent,
+ DummyEmptyLayoutComponent,
+];
+
+@NgModule({
+ imports: [RouterModule],
+ declarations: [...LAYOUTS],
+})
+class DummyLayoutModule {}
+
+@Component({
+ selector: 'abp-dummy',
+ template: '{{route.snapshot.data?.name}} works!',
+})
+class DummyComponent {
route = inject_1(ActivatedRoute);
+
+}
+
+const routes: ABP.Route[] = [
+ {
+ path: '',
+ name: 'Root',
+ },
+ {
+ path: '/parentWithLayout',
+ name: 'ParentWithLayout',
+ parentName: 'Root',
+ layout: eLayoutType.application,
+ },
+ {
+ path: '/parentWithLayout/childWithoutLayout',
+ name: 'ChildWithoutLayout',
+ parentName: 'ParentWithLayout',
+ },
+ {
+ path: '/parentWithLayout/childWithLayout',
+ name: 'ChildWithLayout',
+ parentName: 'ParentWithLayout',
+ layout: eLayoutType.account,
+ },
+ {
+ path: '/withData',
+ name: 'WithData',
+ layout: eLayoutType.application,
+ },
+];
+
+describe('DynamicLayoutComponent', () => {
+ const createComponent = createRoutingFactory({
+ component: RouterOutletComponent,
+ stubsEnabled: false,
+ declarations: [DummyComponent, DynamicLayoutComponent],
+ mocks: [AbpApplicationConfigurationService, HttpClient],
+ providers: [
+ {
+ provide: RoutesService,
+ useFactory: () => mockRoutesService(),
+ },
+ ReplaceableComponentsService,
+ ],
+ imports: [RouterModule, DummyLayoutModule],
+ routes: [
+ { path: '', component: RouterOutletComponent },
+ {
+ path: 'parentWithLayout',
+ component: DynamicLayoutComponent,
+ children: [
+ {
+ path: 'childWithoutLayout',
+ component: DummyComponent,
+ data: { name: 'childWithoutLayout' },
+ },
+ {
+ path: 'childWithLayout',
+ component: DummyComponent,
+ data: { name: 'childWithLayout' },
+ },
+ ],
+ },
+ {
+ path: 'withData',
+ component: DynamicLayoutComponent,
+ children: [
+ {
+ path: '',
+ component: DummyComponent,
+ data: { name: 'withData' },
+ },
+ ],
+ data: { layout: eLayoutType.empty },
+ },
+ {
+ path: 'withoutLayout',
+ component: DynamicLayoutComponent,
+ children: [
+ {
+ path: '',
+ component: DummyComponent,
+ data: { name: 'withoutLayout' },
+ },
+ ],
+ data: { layout: null },
+ },
+ ],
+ });
+
+ let spectator: SpectatorRouting;
+ let replaceableComponents: ReplaceableComponentsService;
+
+ beforeEach(async () => {
+ spectator = createComponent();
+ replaceableComponents = spectator.inject(ReplaceableComponentsService);
+ const routesService = spectator.inject(RoutesService);
+ routesService.add(routes);
+
+ replaceableComponents.add({
+ key: 'Theme.ApplicationLayoutComponent',
+ component: DummyApplicationLayoutComponent,
+ });
+ replaceableComponents.add({
+ key: 'Theme.AccountLayoutComponent',
+ component: DummyAccountLayoutComponent,
+ });
+ replaceableComponents.add({
+ key: 'Theme.EmptyLayoutComponent',
+ component: DummyEmptyLayoutComponent,
+ });
+ });
+
+ it('should handle application layout from parent abp route and display it', async () => {
+ spectator.router.navigateByUrl('/parentWithLayout/childWithoutLayout');
+ await spectator.fixture.whenStable();
+ spectator.detectComponentChanges();
+ expect(spectator.query('abp-dynamic-layout')).toBeTruthy();
+ expect(spectator.query('abp-layout-application')).toBeTruthy();
+ });
+
+ it('should handle account layout from own property and display it', async () => {
+ spectator.router.navigateByUrl('/parentWithLayout/childWithLayout');
+ await spectator.fixture.whenStable();
+ spectator.detectComponentChanges();
+ expect(spectator.query('abp-layout-account')).toBeTruthy();
+ });
+
+ it('should handle empty layout from route data and display it', async () => {
+ spectator.router.navigateByUrl('/withData');
+ await spectator.fixture.whenStable();
+ spectator.detectComponentChanges();
+ expect(spectator.query('abp-layout-empty')).toBeTruthy();
+ });
+
+ it('should display empty layout when layout is null', async () => {
+ spectator.router.navigateByUrl('/withoutLayout');
+ await spectator.fixture.whenStable();
+ spectator.detectComponentChanges();
+ expect(spectator.query('abp-layout-empty')).toBeTruthy();
+ });
+
+ it('should not display any layout when layouts are empty', async () => {
+ const spy = jest.spyOn(replaceableComponents, 'get');
+ spy.mockReturnValue(null);
+ spectator.detectChanges();
+
+ spectator.router.navigateByUrl('/withoutLayout');
+ await spectator.fixture.whenStable();
+ spectator.detectComponentChanges();
+
+ expect(spectator.query('abp-layout-empty')).toBeFalsy();
+ });
+});
diff --git a/npm/ng-packs/packages/core/src/lib/tests/generator-utils.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/generator-utils.spec.ts
index 6fa861b0eb..0722a2f2b2 100644
--- a/npm/ng-packs/packages/core/src/lib/tests/generator-utils.spec.ts
+++ b/npm/ng-packs/packages/core/src/lib/tests/generator-utils.spec.ts
@@ -1,95 +1,39 @@
-import { generateHash, generatePassword, uuid } from '../utils/generator-utils';
-import { ConfigStateService } from '../services';
+import { generateHash, generatePassword } from '../utils/generator-utils';
describe('GeneratorUtils', () => {
- describe('#uuid', () => {
- test('should generate a uuid', () => {
- const result = uuid();
- expect(typeof result).toBe('string');
- expect(result).toHaveLength(36);
- expect(result).toMatch(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/);
- });
-
- test('should generate different uuids', () => {
- const uuid1 = uuid();
- const uuid2 = uuid();
- expect(uuid1).not.toBe(uuid2);
- });
- });
-
describe('#generateHash', () => {
- test('should generate a hash', () => {
+ test('should generate a hash', async () => {
const hash = generateHash('some content \n with second line');
expect(hash).toBe(1112440527);
});
-
- test('should generate consistent hash for same input', () => {
- const input = 'test string';
- const hash1 = generateHash(input);
- const hash2 = generateHash(input);
- expect(hash1).toBe(hash2);
- });
-
- test('should generate different hashes for different inputs', () => {
- const hash1 = generateHash('test1');
- const hash2 = generateHash('test2');
- expect(hash1).not.toBe(hash2);
- });
});
describe('#generatePassword', () => {
- const lowers = 'abcdefghjkmnpqrstuvwxyz';
- const uppers = 'ABCDEFGHJKMNPQRSTUVWXYZ';
- const numbers = '23456789';
- const specials = '!*_#/+-.';
+ const lowers = 'abcdefghijklmnopqrstuvwxyz';
+ const uppers = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
+ const numbers = '0123456789';
+ const specials = '!@#$%&*()_+{}<>?[]./';
test.each`
- passedPasswordLength | actualPasswordLength
- ${Infinity} | ${128}
- ${129} | ${128}
- ${10} | ${10}
- ${7} | ${7}
- ${6} | ${6}
- ${5} | ${5}
- ${4} | ${4}
- ${2} | ${4}
- ${0} | ${4}
- ${undefined} | ${8}
+ name | charSet | passedPasswordLength | actualPasswordLength
+ ${'lower'} | ${lowers} | ${Infinity} | ${128}
+ ${'lower'} | ${lowers} | ${129} | ${128}
+ ${'lower'} | ${lowers} | ${10} | ${10}
+ ${'lower'} | ${lowers} | ${7} | ${7}
+ ${'upper'} | ${uppers} | ${6} | ${6}
+ ${'number'} | ${numbers} | ${5} | ${5}
+ ${'special'} | ${specials} | ${4} | ${4}
+ ${'special'} | ${specials} | ${2} | ${4}
+ ${'special'} | ${specials} | ${0} | ${4}
+ ${'special'} | ${specials} | ${undefined} | ${8}
`(
- 'should generate password with length $actualPasswordLength when passed $passedPasswordLength',
- ({ passedPasswordLength, actualPasswordLength }) => {
- const password = generatePassword(undefined, passedPasswordLength);
+ 'should have a $name in the password that length is $passwordLength',
+ ({ _, charSet, passedPasswordLength, actualPasswordLength }) => {
+ const password = generatePassword(passedPasswordLength);
expect(password).toHaveLength(actualPasswordLength);
-
-
- expect(hasChar(lowers, password)).toBe(true);
- expect(hasChar(uppers, password)).toBe(true);
- expect(hasChar(numbers, password)).toBe(true);
- expect(hasChar(specials, password)).toBe(true);
+ expect(hasChar(charSet, password)).toBe(true);
},
);
-
- test('should generate different passwords', () => {
- const password1 = generatePassword(undefined, 8);
- const password2 = generatePassword(undefined, 8);
- expect(password1).not.toBe(password2);
- });
-
- test('should generate password with injector', () => {
- const mockConfigState = {
- getSettings: jest.fn().mockReturnValue({
- 'Abp.Identity.Password.RequiredLength': '12'
- })
- };
-
- const mockInjector = {
- get: jest.fn().mockReturnValue(mockConfigState)
- };
-
- const password = generatePassword(mockInjector as any);
- expect(password).toHaveLength(12);
- expect(mockInjector.get).toHaveBeenCalledWith(ConfigStateService);
- });
});
});
diff --git a/npm/ng-packs/packages/core/src/lib/tests/initial-utils.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/initial-utils.spec.ts
index 1f063d6eb9..90100d4613 100644
--- a/npm/ng-packs/packages/core/src/lib/tests/initial-utils.spec.ts
+++ b/npm/ng-packs/packages/core/src/lib/tests/initial-utils.spec.ts
@@ -1,6 +1,6 @@
-import { Component } from '@angular/core';
+import { Component, Injector } from '@angular/core';
import { createComponentFactory, Spectator } from '@ngneat/spectator/jest';
-import { of, throwError } from 'rxjs';
+import { of } from 'rxjs';
import { AbpApplicationConfigurationService } from '../proxy/volo/abp/asp-net-core/mvc/application-configurations/abp-application-configuration.service';
import { ApplicationConfigurationDto } from '../proxy/volo/abp/asp-net-core/mvc/application-configurations/models';
import { SessionStateService } from '../services/session-state.service';
@@ -13,8 +13,6 @@ import * as environmentUtils from '../utils/environment-utils';
import * as multiTenancyUtils from '../utils/multi-tenancy-utils';
import { RestService } from '../services/rest.service';
import { CHECK_AUTHENTICATION_STATE_FN_KEY } from '../tokens/check-authentication-state';
-import { APP_INIT_ERROR_HANDLERS } from '../tokens/app-config.token';
-import { TestBed } from '@angular/core/testing';
const environment = { oAuthConfig: { issuer: 'test' } };
@@ -42,18 +40,12 @@ describe('InitialUtils', () => {
useValue: {
environment,
registerLocaleFn: () => Promise.resolve(),
- skipInitAuthService: false,
- skipGetAppConfiguration: false,
},
},
{
provide: CHECK_AUTHENTICATION_STATE_FN_KEY,
useValue: () => {},
},
- {
- provide: APP_INIT_ERROR_HANDLERS,
- useValue: [],
- },
],
});
@@ -64,6 +56,8 @@ describe('InitialUtils', () => {
const environmentService = spectator.inject(EnvironmentService);
const configStateService = spectator.inject(ConfigStateService);
const sessionStateService = spectator.inject(SessionStateService);
+ //const checkAuthenticationState = spectator.inject(CHECK_AUTHENTICATION_STATE_FN_KEY);
+
const authService = spectator.inject(AuthService);
const parseTenantFromUrlSpy = jest.spyOn(multiTenancyUtils, 'parseTenantFromUrl');
@@ -83,60 +77,29 @@ describe('InitialUtils', () => {
const configStateGetOneSpy = jest.spyOn(configStateService, 'getOne');
configStateGetOneSpy.mockReturnValue(appConfigRes.currentTenant);
- await TestBed.runInInjectionContext(() => getInitialData());
+ const mockInjector = {
+ get: spectator.inject,
+ };
- expect(typeof getInitialData).toBe('function');
+ await getInitialData(mockInjector)();
+
+ expect(typeof getInitialData(mockInjector)).toBe('function');
expect(configRefreshAppStateSpy).toHaveBeenCalled();
expect(environmentSetStateSpy).toHaveBeenCalledWith(environment);
expect(sessionSetTenantSpy).toHaveBeenCalledWith(appConfigRes.currentTenant);
expect(authServiceInitSpy).toHaveBeenCalled();
});
-
- test('should handle errors when refreshAppState fails', async () => {
- const configStateService = spectator.inject(ConfigStateService);
- const errorHandlers = spectator.inject(APP_INIT_ERROR_HANDLERS);
-
- const mockError = new Error('Configuration failed');
- const configRefreshAppStateSpy = jest.spyOn(configStateService, 'refreshAppState');
- configRefreshAppStateSpy.mockReturnValue(throwError(() => mockError));
-
- const errorHandlerSpy = jest.fn();
- errorHandlers.push(errorHandlerSpy);
-
- await expect(TestBed.runInInjectionContext(() => getInitialData())).rejects.toThrow('Configuration failed');
- expect(errorHandlerSpy).toHaveBeenCalledWith(mockError);
- });
-
- test('should skip auth service initialization when skipInitAuthService is true', async () => {
- const authService = spectator.inject(AuthService);
- const authServiceInitSpy = jest.spyOn(authService, 'init');
-
- const originalOptions = spectator.inject(CORE_OPTIONS);
- const modifiedOptions = { ...originalOptions, skipInitAuthService: true };
-
- expect(authServiceInitSpy).not.toHaveBeenCalled();
- });
});
describe('#localeInitializer', () => {
test('should resolve registerLocale', async () => {
- expect(typeof localeInitializer).toBe('function');
-
- const sessionStateService = spectator.inject(SessionStateService);
- const getLanguageSpy = jest.spyOn(sessionStateService, 'getLanguage');
- getLanguageSpy.mockReturnValue('en');
-
- const result = await TestBed.runInInjectionContext(() => localeInitializer());
- expect(result).toBe('resolved');
- });
-
- test('should use default language when session language is not set', async () => {
- const sessionStateService = spectator.inject(SessionStateService);
- const getLanguageSpy = jest.spyOn(sessionStateService, 'getLanguage');
- getLanguageSpy.mockReturnValue(null);
-
- const result = await TestBed.runInInjectionContext(() => localeInitializer());
- expect(result).toBe('resolved');
+ const injector = spectator.inject(Injector);
+ const injectorSpy = jest.spyOn(injector, 'get');
+ const sessionState = spectator.inject(SessionStateService);
+ injectorSpy.mockReturnValueOnce(sessionState);
+ injectorSpy.mockReturnValueOnce({ registerLocaleFn: () => Promise.resolve() });
+ expect(typeof localeInitializer(injector)).toBe('function');
+ expect(await localeInitializer(injector)()).toBe('resolved');
});
});
});
diff --git a/npm/ng-packs/packages/core/src/lib/tests/lazy-load.service.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/lazy-load.service.spec.ts
index 5677545f54..c209170c5a 100644
--- a/npm/ng-packs/packages/core/src/lib/tests/lazy-load.service.spec.ts
+++ b/npm/ng-packs/packages/core/src/lib/tests/lazy-load.service.spec.ts
@@ -1,4 +1,3 @@
-import { TestBed } from '@angular/core/testing';
import { of, throwError } from 'rxjs';
import { switchMap } from 'rxjs/operators';
import { LazyLoadService } from '../services/lazy-load.service';
@@ -6,27 +5,9 @@ import { ScriptLoadingStrategy } from '../strategies/loading.strategy';
import { ResourceWaitService } from '../services/resource-wait.service';
describe('LazyLoadService', () => {
- let service: LazyLoadService;
- let resourceWaitService: ResourceWaitService;
-
- beforeEach(() => {
- TestBed.configureTestingModule({
- providers: [
- LazyLoadService,
- {
- provide: ResourceWaitService,
- useValue: {
- addResource: jest.fn(),
- deleteResource: jest.fn(),
- },
- },
- ],
- });
- service = TestBed.inject(LazyLoadService);
- resourceWaitService = TestBed.inject(ResourceWaitService);
- });
-
describe('#load', () => {
+ const resourceWaitService = new ResourceWaitService();
+ const service = new LazyLoadService(resourceWaitService);
const strategy = new ScriptLoadingStrategy('http://example.com/');
afterEach(() => {
@@ -47,10 +28,8 @@ describe('LazyLoadService', () => {
service.load(strategy, 5, 0).subscribe({
error: errorEvent => {
expect(errorEvent).toEqual(new CustomEvent('error'));
- expect(counter).toHaveBeenCalledTimes(5);
+ expect(counter).toHaveBeenCalledTimes(6);
expect(service.loaded.has(strategy.path)).toBe(false);
- expect(resourceWaitService.addResource).toHaveBeenCalledWith(strategy.path);
- expect(resourceWaitService.deleteResource).not.toHaveBeenCalled();
done();
},
});
@@ -64,8 +43,6 @@ describe('LazyLoadService', () => {
next: event => {
expect(event).toBe(loadEvent);
expect(service.loaded.has(strategy.path)).toBe(true);
- expect(resourceWaitService.addResource).toHaveBeenCalledWith(strategy.path);
- expect(resourceWaitService.deleteResource).toHaveBeenCalledWith(strategy.path);
done();
},
});
@@ -77,39 +54,14 @@ describe('LazyLoadService', () => {
service.load(strategy).subscribe(event => {
expect(event).toEqual(loadEvent);
- expect(resourceWaitService.addResource).not.toHaveBeenCalled();
- expect(resourceWaitService.deleteResource).not.toHaveBeenCalled();
done();
});
});
-
- it('should call ResourceWaitService methods correctly', done => {
- const loadEvent = new CustomEvent('load');
- jest.spyOn(strategy, 'createStream').mockReturnValue(of(loadEvent));
-
- service.load(strategy).subscribe({
- next: event => {
- expect(resourceWaitService.addResource).toHaveBeenCalledWith(strategy.path);
- expect(resourceWaitService.deleteResource).toHaveBeenCalledWith(strategy.path);
- done();
- },
- });
- });
-
- it('should store strategy element in loaded map', done => {
- const loadEvent = new CustomEvent('load');
- jest.spyOn(strategy, 'createStream').mockReturnValue(of(loadEvent));
-
- service.load(strategy).subscribe({
- next: event => {
- expect(service.loaded.get(strategy.path)).toBe(strategy.element);
- done();
- },
- });
- });
});
describe('#remove', () => {
+ const resourceWaitService = new ResourceWaitService();
+ const service = new LazyLoadService(resourceWaitService);
it('should remove an already lazy loaded element and return true', () => {
const script = document.createElement('script');
@@ -132,23 +84,5 @@ describe('LazyLoadService', () => {
expect(result).toBe(false);
});
-
- it('should return false when element is null', () => {
- service.loaded.set('foo', null);
-
- const result = service.remove('foo');
-
- expect(result).toBe(false);
- });
-
- it('should handle element without parent node', () => {
- const script = document.createElement('script');
- service.loaded.set('x', script);
-
- const result = service.remove('x');
-
- expect(service.loaded.has('x')).toBe(false);
- expect(result).toBe(true);
- });
});
});
diff --git a/npm/ng-packs/packages/core/src/lib/tests/localization.service.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/localization.service.spec.ts
index 8ef2c7eba6..d2eb653a85 100644
--- a/npm/ng-packs/packages/core/src/lib/tests/localization.service.spec.ts
+++ b/npm/ng-packs/packages/core/src/lib/tests/localization.service.spec.ts
@@ -1,284 +1,282 @@
-import { TestBed } from '@angular/core/testing';
-import { of } from 'rxjs';
-import { LocalizationService } from '../services/localization.service';
+import { Injector } from '@angular/core';
+import { Router } from '@angular/router';
+import { createServiceFactory, SpectatorService, SpyObject } from '@ngneat/spectator/jest';
+import { BehaviorSubject } from 'rxjs';
+import { AbpApplicationConfigurationService } from '../proxy/volo/abp/asp-net-core/mvc/application-configurations/abp-application-configuration.service';
import { ConfigStateService } from '../services/config-state.service';
import { SessionStateService } from '../services/session-state.service';
+import { LocalizationService } from '../services/localization.service';
import { CORE_OPTIONS } from '../tokens/options.token';
-import { ABP } from '../models/common';
+import { CONFIG_STATE_DATA } from './config-state.service.spec';
+import { AbpApplicationLocalizationService } from '../proxy/volo/abp/asp-net-core/mvc/application-configurations/abp-application-localization.service';
+import { APPLICATION_LOCALIZATION_DATA } from './application-localization.service.spec';
+import { IncludeLocalizationResourcesProvider } from '../providers';
+
+const appConfigData$ = new BehaviorSubject(CONFIG_STATE_DATA);
+const appLocalizationData$ = new BehaviorSubject(APPLICATION_LOCALIZATION_DATA);
describe('LocalizationService', () => {
+ let spectator: SpectatorService;
+ let sessionState: SpyObject;
+ let configState: SpyObject;
let service: LocalizationService;
- let sessionState: SessionStateService;
- let configState: ConfigStateService;
- const mockLocalizationData = {
- defaultResourceName: 'MyProjectName',
- values: {
- MyProjectName: {
- 'Welcome': 'Welcome',
- 'Hello {0}': 'Hello {0}',
+ const createService = createServiceFactory({
+ service: LocalizationService,
+ entryComponents: [],
+ mocks: [Router],
+ providers: [
+ IncludeLocalizationResourcesProvider,
+ {
+ provide: CORE_OPTIONS,
+ useValue: { registerLocaleFn: () => Promise.resolve(), cultureNameLocaleFileMap: {} },
},
- AbpIdentity: {
- 'Identity': 'Identity',
- 'User': 'User',
+ {
+ provide: AbpApplicationConfigurationService,
+ useValue: { get: () => appConfigData$ },
},
- },
- };
-
- const mockLocalizationsMap = new Map>();
- mockLocalizationsMap.set('AbpIdentity', { 'Identity': 'Identity', 'User': 'User' });
- mockLocalizationsMap.set('MyProjectName', { 'Welcome': 'Welcome', 'Hello {0}': 'Hello {0}' });
+ {
+ provide: AbpApplicationLocalizationService,
+ useValue: { get: () => appLocalizationData$ },
+ },
+ ],
+ });
beforeEach(() => {
- TestBed.configureTestingModule({
- providers: [
- LocalizationService,
- {
- provide: CORE_OPTIONS,
- useValue: {
- registerLocaleFn: () => Promise.resolve(),
- cultureNameLocaleFileMap: {}
- },
- },
- {
- provide: ConfigStateService,
- useValue: {
- refreshAppState: jest.fn(),
- getDeep: jest.fn().mockReturnValue({
- localization: {
- currentCulture: { cultureName: 'tr' },
- defaultResourceName: 'MyProjectName',
- values: mockLocalizationData.values,
- },
- }),
- getDeep$: jest.fn().mockReturnValue(of({
- localization: {
- currentCulture: { cultureName: 'tr' },
- defaultResourceName: 'MyProjectName',
- values: mockLocalizationData.values,
- },
- })),
- getOne: jest.fn().mockReturnValue(mockLocalizationData),
- getOne$: jest.fn().mockReturnValue(of(mockLocalizationData)),
- getAll: jest.fn().mockReturnValue({
- localization: mockLocalizationData,
- }),
- getAll$: jest.fn().mockReturnValue(of({
- localization: mockLocalizationData,
- })),
- refreshLocalization: jest.fn().mockReturnValue(of({})),
- },
- },
- {
- provide: SessionStateService,
- useValue: {
- setLanguage: jest.fn(),
- setTenant: jest.fn(),
- setInitialLanguage: jest.fn(),
- getLanguage: jest.fn().mockReturnValue('tr'),
- getTenant: jest.fn().mockReturnValue(null),
- getInitialLanguage: jest.fn().mockReturnValue('tr'),
- onLanguageChange$: jest.fn().mockReturnValue(of('tr')),
- getLanguage$: jest.fn().mockReturnValue(of('tr')),
- },
- },
- ],
- });
- service = TestBed.inject(LocalizationService);
- sessionState = TestBed.inject(SessionStateService);
- configState = TestBed.inject(ConfigStateService);
+ spectator = createService();
+ sessionState = spectator.inject(SessionStateService);
+ configState = spectator.inject(ConfigStateService);
+ service = spectator.service;
- (service as any).localizations$.next(mockLocalizationsMap);
+ configState.refreshAppState();
+ sessionState.setLanguage('tr');
+ appConfigData$.next(CONFIG_STATE_DATA);
});
describe('#currentLang', () => {
- it('should return current language', () => {
- expect(service.currentLang).toBe('tr');
- });
-
- it('should return observable of current language', (done) => {
- service.currentLang$.subscribe(lang => {
- expect(lang).toBe('tr');
+ it('should be tr', done => {
+ setTimeout(() => {
+ expect(service.currentLang).toBe('tr');
done();
- });
- });
- });
-
- describe('#languageChange$', () => {
- it('should emit language changes', (done) => {
- service.languageChange$.subscribe(lang => {
- expect(lang).toBe('tr');
- done();
- });
-
- (service as any)._languageChange$.next('tr');
+ }, 0);
});
});
describe('#get', () => {
- it('should return observable localization for valid key', (done) => {
- service.get('AbpIdentity::Identity').subscribe(result => {
- expect(result).toBe('Identity');
- done();
- });
- });
-
- it('should return key when localization not found', (done) => {
- service.get('AbpIdentity::NonExistent').subscribe(result => {
- expect(result).toBe('NonExistent');
- done();
- });
- });
-
- it('should handle interpolation', (done) => {
- service.get('MyProjectName::Hello {0}', 'John').subscribe(result => {
- expect(result).toBe('Hello John');
+ it('should be return an observable localization', done => {
+ service.get('AbpIdentity::Identity').subscribe(localization => {
+ expect(localization).toBe(CONFIG_STATE_DATA.localization.values.AbpIdentity.Identity);
done();
});
});
});
describe('#instant', () => {
- it('should return localization for valid key', () => {
- const result = service.instant('AbpIdentity::Identity');
- expect(result).toBe('Identity');
- });
+ it('should be return a localization', () => {
+ const localization = service.instant('AbpIdentity::Identity');
- it('should return key when localization not found', () => {
- const result = service.instant('AbpIdentity::NonExistent');
- expect(result).toBe('NonExistent');
+ expect(localization).toBe(CONFIG_STATE_DATA.localization.values.AbpIdentity.Identity);
});
+ });
- it('should handle interpolation', () => {
- const result = service.instant('MyProjectName::Hello {0}', 'John');
- expect(result).toBe('Hello John');
+ describe('#registerLocale', () => {
+ it('should throw an error message when service have an otherInstance', async () => {
+ try {
+ const instance = new LocalizationService(
+ sessionState,
+ spectator.inject(Injector),
+ null,
+ configState,
+ );
+ } catch (error) {
+ expect((error as Error).message).toBe('LocalizationService should have only one instance.');
+ }
});
});
describe('#localize', () => {
- it('should return observable localization for valid resource and key', (done) => {
- service.localize('AbpIdentity', 'Identity', 'Default').subscribe(result => {
- expect(result).toBe('Identity');
- done();
- });
- });
-
- it('should return default value when key not found', (done) => {
- service.localize('AbpIdentity', 'NonExistent', 'Default').subscribe(result => {
- expect(result).toBe('Default');
- done();
- });
- });
+ test.each`
+ resource | key | defaultValue | expected
+ ${'_'} | ${'TEST'} | ${'DEFAULT'} | ${'TEST'}
+ ${'foo'} | ${'bar'} | ${'DEFAULT'} | ${'baz'}
+ ${'x'} | ${'bar'} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${'a'} | ${'bar'} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${''} | ${'bar'} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${undefined} | ${'bar'} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${'foo'} | ${'y'} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${'x'} | ${'y'} | ${'DEFAULT'} | ${'z'}
+ ${'a'} | ${'y'} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${''} | ${'y'} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${undefined} | ${'y'} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${'foo'} | ${''} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${'x'} | ${''} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${'a'} | ${''} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${''} | ${''} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${undefined} | ${''} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${'foo'} | ${undefined} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${'x'} | ${undefined} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${'a'} | ${undefined} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${''} | ${undefined} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${undefined} | ${undefined} | ${'DEFAULT'} | ${'DEFAULT'}
+ `(
+ 'should return observable $expected when resource name is $resource and key is $key',
+ async ({ resource, key, defaultValue, expected }) => {
+ appConfigData$.next({
+ localization: {
+ values: { foo: { bar: 'baz' }, x: { y: 'z' } },
+ defaultResourceName: 'x',
+ },
+ } as any);
+ configState.refreshAppState();
- it('should return default value when resource not found', (done) => {
- service.localize('NonExistent', 'Identity', 'Default').subscribe(result => {
- expect(result).toBe('Default');
- done();
- });
- });
+ service.localize(resource, key, defaultValue).subscribe(result => {
+ expect(result).toBe(expected);
+ });
+ },
+ );
});
describe('#localizeSync', () => {
- it('should return localization for valid resource and key', () => {
- const result = service.localizeSync('AbpIdentity', 'Identity', 'Default');
- expect(result).toBe('Identity');
- });
+ test.each`
+ resource | key | defaultValue | expected
+ ${'_'} | ${'TEST'} | ${'DEFAULT'} | ${'TEST'}
+ ${'foo'} | ${'bar'} | ${'DEFAULT'} | ${'baz'}
+ ${'x'} | ${'bar'} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${'a'} | ${'bar'} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${''} | ${'bar'} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${undefined} | ${'bar'} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${'foo'} | ${'y'} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${'x'} | ${'y'} | ${'DEFAULT'} | ${'z'}
+ ${'a'} | ${'y'} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${''} | ${'y'} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${undefined} | ${'y'} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${'foo'} | ${''} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${'x'} | ${''} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${'a'} | ${''} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${''} | ${''} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${undefined} | ${''} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${'foo'} | ${undefined} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${'x'} | ${undefined} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${'a'} | ${undefined} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${''} | ${undefined} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${undefined} | ${undefined} | ${'DEFAULT'} | ${'DEFAULT'}
+ `(
+ 'should return $expected when resource name is $resource and key is $key',
+ ({ resource, key, defaultValue, expected }) => {
+ appConfigData$.next({
+ localization: {
+ values: { foo: { bar: 'baz' }, x: { y: 'z' } },
+ defaultResourceName: 'x',
+ },
+ } as any);
+ configState.refreshAppState();
- it('should return default value when key not found', () => {
- const result = service.localizeSync('AbpIdentity', 'NonExistent', 'Default');
- expect(result).toBe('Default');
- });
+ const result = service.localizeSync(resource, key, defaultValue);
- it('should return default value when resource not found', () => {
- const result = service.localizeSync('NonExistent', 'Identity', 'Default');
- expect(result).toBe('Default');
- });
+ expect(result).toBe(expected);
+ },
+ );
});
describe('#localizeWithFallback', () => {
- it('should return observable localization from first available resource', (done) => {
- service.localizeWithFallback(['AbpIdentity', 'MyProjectName'], ['Identity'], 'Default').subscribe(result => {
- expect(result).toBe('Identity');
- done();
- });
- });
+ test.each`
+ resources | keys | defaultValue | expected
+ ${['', '_']} | ${['TEST', 'OTHER']} | ${'DEFAULT'} | ${'TEST'}
+ ${['foo']} | ${['bar']} | ${'DEFAULT'} | ${'baz'}
+ ${['x']} | ${['bar']} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${['a', 'b', 'c']} | ${['bar']} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${['']} | ${['bar']} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${[]} | ${['bar']} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${['foo']} | ${['y']} | ${'DEFAULT'} | ${'z'}
+ ${['x']} | ${['y']} | ${'DEFAULT'} | ${'z'}
+ ${['a', 'b', 'c']} | ${['y']} | ${'DEFAULT'} | ${'z'}
+ ${['']} | ${['y']} | ${'DEFAULT'} | ${'z'}
+ ${[]} | ${['y']} | ${'DEFAULT'} | ${'z'}
+ ${['foo']} | ${['bar', 'y']} | ${'DEFAULT'} | ${'baz'}
+ ${['x']} | ${['bar', 'y']} | ${'DEFAULT'} | ${'z'}
+ ${['a', 'b', 'c']} | ${['bar', 'y']} | ${'DEFAULT'} | ${'z'}
+ ${['']} | ${['bar', 'y']} | ${'DEFAULT'} | ${'z'}
+ ${[]} | ${['bar', 'y']} | ${'DEFAULT'} | ${'z'}
+ ${['foo']} | ${['']} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${['x']} | ${['']} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${['a', 'b', 'c']} | ${['']} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${['']} | ${['']} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${[]} | ${['']} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${['foo']} | ${[]} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${['x']} | ${[]} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${['a', 'b', 'c']} | ${[]} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${['']} | ${[]} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${[]} | ${[]} | ${'DEFAULT'} | ${'DEFAULT'}
+ `(
+ 'should return observable $expected when resource names are $resources and keys are $keys',
+ async ({ resources, keys, defaultValue, expected }) => {
+ appConfigData$.next({
+ localization: {
+ values: { foo: { bar: 'baz' }, x: { y: 'z' } },
+ defaultResourceName: 'x',
+ },
+ } as any);
+ configState.refreshAppState();
- it('should return default value when no resource has the key', (done) => {
- service.localizeWithFallback(['AbpIdentity', 'MyProjectName'], ['NonExistent'], 'Default').subscribe(result => {
- expect(result).toBe('Default');
- done();
- });
- });
+ service.localizeWithFallback(resources, keys, defaultValue).subscribe(result => {
+ expect(result).toBe(expected);
+ });
+ },
+ );
});
describe('#localizeWithFallbackSync', () => {
- it('should return localization from first available resource', () => {
- const result = service.localizeWithFallbackSync(['AbpIdentity', 'MyProjectName'], ['Identity'], 'Default');
- expect(result).toBe('Identity');
- });
-
- it('should return default value when no resource has the key', () => {
- const result = service.localizeWithFallbackSync(['AbpIdentity', 'MyProjectName'], ['NonExistent'], 'Default');
- expect(result).toBe('Default');
- });
- });
-
- describe('#getResource', () => {
- it('should return resource for valid resource name', () => {
- const resource = service.getResource('AbpIdentity');
- expect(resource).toBeDefined();
- expect(resource?.['Identity']).toBe('Identity');
- });
-
- it('should return undefined for non-existent resource', () => {
- const resource = service.getResource('NonExistent');
- expect(resource).toBeUndefined();
- });
- });
-
- describe('#getResource$', () => {
- it('should return observable resource for valid resource name', (done) => {
- service.getResource$('AbpIdentity').subscribe(resource => {
- expect(resource).toBeDefined();
- expect(resource?.['Identity']).toBe('Identity');
- done();
- });
- });
-
- it('should return observable undefined for non-existent resource', (done) => {
- service.getResource$('NonExistent').subscribe(resource => {
- expect(resource).toBeUndefined();
- done();
- });
- });
- });
+ test.each`
+ resources | keys | defaultValue | expected
+ ${['', '_']} | ${['TEST', 'OTHER']} | ${'DEFAULT'} | ${'TEST'}
+ ${['foo']} | ${['bar']} | ${'DEFAULT'} | ${'baz'}
+ ${['x']} | ${['bar']} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${['a', 'b', 'c']} | ${['bar']} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${['']} | ${['bar']} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${[]} | ${['bar']} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${['foo']} | ${['y']} | ${'DEFAULT'} | ${'z'}
+ ${['x']} | ${['y']} | ${'DEFAULT'} | ${'z'}
+ ${['a', 'b', 'c']} | ${['y']} | ${'DEFAULT'} | ${'z'}
+ ${['']} | ${['y']} | ${'DEFAULT'} | ${'z'}
+ ${[]} | ${['y']} | ${'DEFAULT'} | ${'z'}
+ ${['foo']} | ${['bar', 'y']} | ${'DEFAULT'} | ${'baz'}
+ ${['x']} | ${['bar', 'y']} | ${'DEFAULT'} | ${'z'}
+ ${['a', 'b', 'c']} | ${['bar', 'y']} | ${'DEFAULT'} | ${'z'}
+ ${['']} | ${['bar', 'y']} | ${'DEFAULT'} | ${'z'}
+ ${[]} | ${['bar', 'y']} | ${'DEFAULT'} | ${'z'}
+ ${['foo']} | ${['']} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${['x']} | ${['']} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${['a', 'b', 'c']} | ${['']} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${['']} | ${['']} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${[]} | ${['']} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${['foo']} | ${[]} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${['x']} | ${[]} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${['a', 'b', 'c']} | ${[]} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${['']} | ${[]} | ${'DEFAULT'} | ${'DEFAULT'}
+ ${[]} | ${[]} | ${'DEFAULT'} | ${'DEFAULT'}
+ `(
+ 'should return $expected when resource names are $resources and keys are $keys',
+ ({ resources, keys, defaultValue, expected }) => {
+ appConfigData$.next({
+ localization: {
+ values: { foo: { bar: 'baz' }, x: { y: 'z' } },
+ defaultResourceName: 'x',
+ },
+ } as any);
+ configState.refreshAppState();
- describe('#addLocalization', () => {
- it('should add localization data', () => {
- const localizations: ABP.Localization[] = [
- {
- culture: 'en',
- resources: [
- {
- resourceName: 'TestResource',
- texts: {
- 'TestKey': 'TestValue',
- },
- },
- ],
- },
- ];
+ const result = service.localizeWithFallbackSync(resources, keys, defaultValue);
- service.addLocalization(localizations);
-
- expect(() => service.addLocalization(localizations)).not.toThrow();
- });
+ expect(result).toBe(expected);
+ },
+ );
});
- describe('#registerLocale', () => {
- it('should register locale successfully', async () => {
- const result = await service.registerLocale('en');
- expect(result).toBeUndefined();
+ describe('#getLocalization', () => {
+ it('should return a localization', () => {
+ expect(
+ service.instant("MyProjectName::'{0}' and '{1}' do not match.", 'first', 'second'),
+ ).toBe('first and second do not match.');
});
});
});
diff --git a/npm/ng-packs/packages/core/src/lib/tests/ng-model.component.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/ng-model.component.spec.ts
index 1e194ffe5f..fbb19ac3fc 100644
--- a/npm/ng-packs/packages/core/src/lib/tests/ng-model.component.spec.ts
+++ b/npm/ng-packs/packages/core/src/lib/tests/ng-model.component.spec.ts
@@ -7,8 +7,6 @@ import { AbstractNgModelComponent } from '../abstracts';
@Component({
selector: 'abp-test',
template: '',
- standalone: true,
- imports: [AbstractNgModelComponent],
providers: [
{
provide: NG_VALUE_ACCESSOR,
@@ -19,17 +17,8 @@ import { AbstractNgModelComponent } from '../abstracts';
})
export class TestComponent extends AbstractNgModelComponent implements OnInit {
@Input() override: boolean;
- @Input() testValueFn: (value: any, previousValue?: any) => any;
- @Input() testValueLimitFn: (value: any, previousValue?: any) => any;
ngOnInit() {
- if (this.testValueFn) {
- this.valueFn = this.testValueFn;
- }
- if (this.testValueLimitFn) {
- this.valueLimitFn = this.testValueLimitFn;
- }
-
setTimeout(() => {
if (this.override) {
this.value = 'test';
@@ -39,20 +28,19 @@ export class TestComponent extends AbstractNgModelComponent implements OnInit {
}
describe('AbstractNgModelComponent', () => {
- let spectator: SpectatorHost;
+ let spectator: SpectatorHost;
const createHost = createHostFactory({
component: TestComponent,
+ declarations: [AbstractNgModelComponent],
imports: [FormsModule],
});
beforeEach(() => {
- spectator = createHost('', {
+ spectator = createHost('', {
hostProps: {
val: '1',
override: false,
- testValueFn: undefined,
- testValueLimitFn: undefined,
},
});
});
@@ -72,83 +60,4 @@ describe('AbstractNgModelComponent', () => {
done();
});
});
-
- test('should handle valueFn input', () => {
- const valueFn = jest.fn((value: any) => value + '_transformed');
- spectator.component.valueFn = valueFn;
- spectator.component.value = 'original';
-
- expect(valueFn).toHaveBeenCalledWith('original', '1');
- expect(spectator.component.value).toBe('original_transformed');
- });
-
- test('should handle valueLimitFn input', () => {
- const valueLimitFn = jest.fn((value: any) => value === 'blocked' ? false : value);
- spectator.component.valueLimitFn = valueLimitFn;
- spectator.component.value = 'allowed';
-
- expect(valueLimitFn).toHaveBeenCalledWith('allowed', '1');
- expect(spectator.component.value).toBe('1');
- });
-
- test('should block value when valueLimitFn returns false', () => {
- const valueLimitFn = jest.fn((value: any) => value === 'blocked' ? false : value);
- spectator.component.valueLimitFn = valueLimitFn;
- const originalValue = spectator.component.value;
- spectator.component.value = 'blocked';
-
- expect(valueLimitFn).toHaveBeenCalledWith('blocked', originalValue);
- expect(spectator.component.value).toBe('blocked');
- });
-
- test('should handle disabled state', () => {
- spectator.component.setDisabledState(true);
- expect(spectator.component.disabled).toBe(true);
- });
-
- test('should handle readonly state', () => {
- spectator.component.readonly = true;
- const originalValue = spectator.component.value;
- spectator.component.value = 'new_value';
-
- expect(spectator.component.value).toBe(originalValue);
- });
-
- test('should register onChange callback', () => {
- const onChangeSpy = jest.fn();
- spectator.component.registerOnChange(onChangeSpy);
-
- spectator.component.value = 'new_value';
- expect(onChangeSpy).toHaveBeenCalledWith('new_value');
- });
-
- test('should register onTouched callback', () => {
- const onTouchedSpy = jest.fn();
- spectator.component.registerOnTouched(onTouchedSpy);
-
- expect(spectator.component.onTouched).toBe(onTouchedSpy);
- });
-
- test('should notify value change', () => {
- const onChangeSpy = jest.fn();
- spectator.component.registerOnChange(onChangeSpy);
-
- spectator.component.notifyValueChange();
- expect(onChangeSpy).toHaveBeenCalledWith(spectator.component.value);
- });
-
- test('should write value correctly', () => {
- const valueLimitFn = jest.fn((value: any) => value);
- spectator.component.valueLimitFn = valueLimitFn;
-
- spectator.component.writeValue('new_written_value');
- expect(valueLimitFn).toHaveBeenCalledWith('new_written_value', '1');
- expect(spectator.component.value).toBe('new_written_value');
- });
-
- test('should handle default value', () => {
- (spectator.component as any)._value = undefined;
- expect(spectator.component.value).toBe(undefined);
- expect(spectator.component.defaultValue).toBe(undefined);
- });
});
diff --git a/npm/ng-packs/packages/core/src/lib/tests/permission.directive.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/permission.directive.spec.ts
index ad2f2d7d07..f4d32d0be8 100644
--- a/npm/ng-packs/packages/core/src/lib/tests/permission.directive.spec.ts
+++ b/npm/ng-packs/packages/core/src/lib/tests/permission.directive.spec.ts
@@ -3,7 +3,6 @@ import { Subject } from 'rxjs';
import { PermissionDirective } from '../directives/permission.directive';
import { PermissionService } from '../services/permission.service';
import { ChangeDetectorRef } from '@angular/core';
-import { QUEUE_MANAGER } from '../tokens/queue.token';
describe('PermissionDirective', () => {
let spectator: SpectatorDirective;
@@ -14,7 +13,6 @@ describe('PermissionDirective', () => {
directive: PermissionDirective,
providers: [
{ provide: PermissionService, useValue: { getGrantedPolicy$: () => grantedPolicy$ } },
- { provide: QUEUE_MANAGER, useValue: { add: jest.fn(), remove: jest.fn() } },
],
});
@@ -84,7 +82,7 @@ describe('PermissionDirective', () => {
const detectChanges = jest.spyOn(cdr, 'detectChanges');
spectator.setHostInput({ condition: 'test' });
grantedPolicy$.next(true);
-
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
directive.onInit = () => {
expect(detectChanges).not.toHaveBeenCalled();
diff --git a/npm/ng-packs/packages/core/src/lib/tests/permission.guard.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/permission.guard.spec.ts
index 666c3bef5c..68e47053fd 100644
--- a/npm/ng-packs/packages/core/src/lib/tests/permission.guard.spec.ts
+++ b/npm/ng-packs/packages/core/src/lib/tests/permission.guard.spec.ts
@@ -14,6 +14,7 @@ import { HttpErrorReporterService } from '../services/http-error-reporter.servic
import { PermissionService } from '../services/permission.service';
import { RoutesService } from '../services/routes.service';
import { CORE_OPTIONS } from '../tokens/options.token';
+import { IncludeLocalizationResourcesProvider, provideAbpCore, withOptions } from '../providers';
import { TestBed } from '@angular/core/testing';
import { RouterTestingHarness } from '@angular/router/testing';
import { OTHERS_GROUP } from '../tokens';
@@ -21,10 +22,6 @@ import { SORT_COMPARE_FUNC, compareFuncFactory } from '../tokens/compare-func.to
import { AuthService } from '../abstracts';
describe('PermissionGuard', () => {
- beforeAll(() => {
- jest.setTimeout(60000);
- });
-
let spectator: SpectatorService;
let guard: PermissionGuard;
let routes: SpyObject;
@@ -35,12 +32,13 @@ describe('PermissionGuard', () => {
isAuthenticated: true,
};
- @Component({ template: '', standalone: true })
+ @Component({ template: '' })
class DummyComponent {}
const createService = createServiceFactory({
service: PermissionGuard,
mocks: [PermissionService],
+ declarations: [DummyComponent],
imports: [
HttpClientTestingModule,
RouterModule.forRoot([
@@ -52,7 +50,6 @@ describe('PermissionGuard', () => {
},
},
]),
- DummyComponent,
],
providers: [
{
@@ -60,15 +57,10 @@ describe('PermissionGuard', () => {
useValue: '/',
},
{ provide: AuthService, useValue: mockOAuthService },
- {
- provide: CORE_OPTIONS,
- useValue: {
- skipGetAppConfiguration: true,
- environment: { remoteEnv: {} }
- }
- },
+ { provide: CORE_OPTIONS, useValue: { skipGetAppConfiguration: true } },
{ provide: OTHERS_GROUP, useValue: 'AbpUi::OthersGroup' },
{ provide: SORT_COMPARE_FUNC, useValue: compareFuncFactory },
+ IncludeLocalizationResourcesProvider,
],
});
@@ -90,24 +82,17 @@ describe('PermissionGuard', () => {
});
});
- it('should not emit value when the grantedPolicy is false', done => {
+ it('should return false and report an error when the grantedPolicy is false', done => {
permissionService.getGrantedPolicy$.andReturn(of(false));
const spy = jest.spyOn(httpErrorReporter, 'reportError');
-
- guard.canActivate({ data: { requiredPolicy: 'test' } } as any, null).subscribe({
- next: res => {
- done.fail('Should not emit value when policy is false');
- },
- error: err => {
- console.error('Test error:', err);
- done.fail(err);
- },
- complete: () => {
- expect(spy).not.toHaveBeenCalled();
- done();
- }
+ guard.canActivate({ data: { requiredPolicy: 'test' } } as any, null).subscribe(res => {
+ expect(res).toBe(false);
+ expect(spy.mock.calls[0][0]).toEqual({
+ status: 403,
+ });
+ done();
});
- }, 30000);
+ });
it('should check the requiredPolicy from RoutesService', done => {
routes.add([
@@ -136,34 +121,6 @@ describe('PermissionGuard', () => {
done();
});
});
-
- it('should not report error when user is not authenticated', done => {
- permissionService.getGrantedPolicy$.andReturn(of(false));
- const spy = jest.spyOn(httpErrorReporter, 'reportError');
-
- const mockAuthService = { isAuthenticated: false };
- (guard as any).authService = mockAuthService;
-
- guard.canActivate({ data: { requiredPolicy: 'test' } } as any, null).subscribe({
- next: res => {
- done.fail('Should not emit value when policy is false');
- },
- complete: () => {
- expect(spy).not.toHaveBeenCalled();
- done();
- }
- });
- });
-
- it('should handle route data with requiredPolicy', done => {
- permissionService.getGrantedPolicy$.andReturn(of(true));
-
- guard.canActivate({ data: { requiredPolicy: 'CustomPolicy' } } as any, null).subscribe(result => {
- expect(result).toBe(true);
- expect(permissionService.getGrantedPolicy$).toHaveBeenCalledWith('CustomPolicy');
- done();
- });
- });
});
@Component({ standalone: true, template: '' })
@@ -202,16 +159,8 @@ describe('authGuard', () => {
{ provide: AuthService, useValue: mockOAuthService },
{ provide: PermissionService, useValue: permissionService },
{ provide: HttpErrorReporterService, useValue: httpErrorReporter },
- {
- provide: CORE_OPTIONS,
- useValue: {
- skipGetAppConfiguration: true,
- environment: { remoteEnv: {} }
- }
- },
- { provide: OTHERS_GROUP, useValue: 'AbpUi::OthersGroup' },
- { provide: SORT_COMPARE_FUNC, useValue: compareFuncFactory },
provideRouter(routes),
+ provideAbpCore(withOptions()),
],
});
});
@@ -224,20 +173,13 @@ describe('authGuard', () => {
expect(httpErrorReporter.reportError).not.toHaveBeenCalled();
});
- it('should not emit value and report an error when the grantedPolicy is false', async () => {
+ it('should return false and report an error when the grantedPolicy is false', async () => {
permissionService.getGrantedPolicy$.andReturn(of(false));
-
- const guard = TestBed.inject(PermissionGuard);
- const spy = jest.spyOn(httpErrorReporter, 'reportError');
-
- guard.canActivate({ data: { requiredPolicy: 'test' } } as any, null).subscribe({
- next: res => {
- fail('Should not emit value when policy is false');
- },
- complete: () => {
- expect(spy).toHaveBeenCalledWith({ status: 403 });
- }
- });
+ await RouterTestingHarness.create('/dummy');
+
+ expect(TestBed.inject(Router).url).not.toEqual('/dummy');
+ expect(httpErrorReporter.reportError).toHaveBeenCalled();
+ expect(httpErrorReporter.reportError).toBeCalledWith({ status: 403 });
});
it('should check the requiredPolicy from RoutesService', async () => {
diff --git a/npm/ng-packs/packages/core/src/lib/tests/projection.strategy.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/projection.strategy.spec.ts
index 6af652d34f..4e9f4cee5b 100644
--- a/npm/ng-packs/packages/core/src/lib/tests/projection.strategy.spec.ts
+++ b/npm/ng-packs/packages/core/src/lib/tests/projection.strategy.spec.ts
@@ -20,7 +20,6 @@ import { CONTEXT_STRATEGY } from '../strategies/context.strategy';
describe('ComponentProjectionStrategy', () => {
@Component({
template: '{{ bar || baz }}
',
- standalone: true,
})
class TestComponent {
bar: string;
@@ -29,7 +28,6 @@ describe('ComponentProjectionStrategy', () => {
@Component({
template: '',
- standalone: true,
})
class HostComponent {
@ViewChild('container', { static: true, read: ViewContainerRef })
@@ -42,7 +40,7 @@ describe('ComponentProjectionStrategy', () => {
const createComponent = createComponentFactory({
component: HostComponent,
- imports: [TestComponent],
+ entryComponents: [TestComponent],
});
beforeEach(() => {
@@ -51,9 +49,7 @@ describe('ComponentProjectionStrategy', () => {
});
afterEach(() => {
- if (componentRef) {
- componentRef.destroy();
- }
+ componentRef.destroy();
spectator.detectChanges();
});
@@ -88,14 +84,13 @@ describe('ComponentProjectionStrategy', () => {
describe('RootComponentProjectionStrategy', () => {
@Component({
template: '{{ bar || baz }}
',
- standalone: true,
})
class TestComponent {
bar: string;
baz = 'baz';
}
- @Component({ template: '', standalone: true })
+ @Component({ template: '' })
class HostComponent {}
let spectator: Spectator;
@@ -103,7 +98,7 @@ describe('RootComponentProjectionStrategy', () => {
const createComponent = createComponentFactory({
component: HostComponent,
- imports: [TestComponent],
+ entryComponents: [TestComponent],
});
beforeEach(() => {
@@ -111,9 +106,7 @@ describe('RootComponentProjectionStrategy', () => {
});
afterEach(() => {
- if (componentRef) {
- componentRef.destroy();
- }
+ componentRef.destroy();
spectator.detectChanges();
});
@@ -151,7 +144,6 @@ describe('TemplateProjectionStrategy', () => {
`,
- standalone: true,
})
class HostComponent {
@ViewChild('container', { static: true, read: ViewContainerRef })
@@ -177,9 +169,7 @@ describe('TemplateProjectionStrategy', () => {
});
afterEach(() => {
- if (embeddedViewRef) {
- embeddedViewRef.destroy();
- }
+ embeddedViewRef.destroy();
spectator.detectChanges();
});
diff --git a/npm/ng-packs/packages/core/src/lib/tests/replaceable-route-container.component.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/replaceable-route-container.component.spec.ts
index 479d465759..9b8b62ef46 100644
--- a/npm/ng-packs/packages/core/src/lib/tests/replaceable-route-container.component.spec.ts
+++ b/npm/ng-packs/packages/core/src/lib/tests/replaceable-route-container.component.spec.ts
@@ -8,14 +8,12 @@ import { ReplaceableComponentsService } from '../services/replaceable-components
@Component({
selector: 'abp-external-component',
template: 'external
',
- standalone: true,
})
export class ExternalComponent {}
@Component({
selector: 'abp-default-component',
template: 'default
',
- standalone: true,
})
export class DefaultComponent {}
@@ -40,7 +38,8 @@ describe('ReplaceableRouteContainerComponent', () => {
{ provide: ActivatedRoute, useValue: activatedRouteMock },
{ provide: ReplaceableComponentsService, useValue: { get$: () => get$Res } },
],
- imports: [ExternalComponent, DefaultComponent],
+ declarations: [ExternalComponent, DefaultComponent],
+ entryComponents: [DefaultComponent, ExternalComponent],
mocks: [Router],
});
diff --git a/npm/ng-packs/packages/core/src/lib/tests/replaceable-template.directive.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/replaceable-template.directive.spec.ts
index ab96a4eacf..94fdf8a527 100644
--- a/npm/ng-packs/packages/core/src/lib/tests/replaceable-template.directive.spec.ts
+++ b/npm/ng-packs/packages/core/src/lib/tests/replaceable-template.directive.spec.ts
@@ -1,176 +1,174 @@
-import { Component, EventEmitter, Input, Output, inject } from '@angular/core';
-import { Router } from '@angular/router';
-import { createDirectiveFactory, SpectatorDirective } from '@ngneat/spectator/jest';
-import { BehaviorSubject } from 'rxjs';
-import { ReplaceableTemplateDirective } from '../directives/replaceable-template.directive';
-import { ReplaceableComponents } from '../models/replaceable-components';
-import { ReplaceableComponentsService } from '../services/replaceable-components.service';
-
-@Component({
- selector: 'abp-default-component',
- template: ' default
',
- exportAs: 'abpDefaultComponent',
- standalone: true,
-})
-class DefaultComponent {
- @Input()
- oneWay;
-
- @Input()
- twoWay: boolean;
-
- @Output()
- readonly twoWayChange = new EventEmitter();
-
- @Output()
- readonly someOutput = new EventEmitter();
-
- setTwoWay(value) {
- this.twoWay = value;
- this.twoWayChange.emit(value);
- }
-}
-
-@Component({
- selector: 'abp-external-component',
- template: ' external
',
- standalone: true,
-})
-class ExternalComponent {
- data = inject>('REPLACEABLE_DATA' as any, { optional: true })!;
-
-}
-
-describe('ReplaceableTemplateDirective', () => {
- let spectator: SpectatorDirective;
- const get$Res = new BehaviorSubject(undefined);
-
- const createDirective = createDirectiveFactory({
- directive: ReplaceableTemplateDirective,
- imports: [DefaultComponent, ExternalComponent],
- mocks: [Router],
- providers: [{ provide: ReplaceableComponentsService, useValue: { get$: () => get$Res } }],
- });
-
- describe('without external component', () => {
- const twoWayChange = jest.fn(a => a);
- const someOutput = jest.fn(a => a);
-
- beforeEach(() => {
- spectator = createDirective(
- `
-
- `,
- {
- hostProps: {
- oneWay: { label: 'Test' },
- twoWay: false,
- twoWayChange,
- someOutput,
- },
- },
- );
-
- const component = spectator.query(DefaultComponent);
- spectator.directive.context.initTemplate(component);
- spectator.detectChanges();
- });
-
- afterEach(() => twoWayChange.mockClear());
-
- it('should display the default template when store response is undefined', () => {
- expect(spectator.query('abp-default-component')).toBeTruthy();
- });
-
- it('should be setted inputs and outputs', () => {
- const component = spectator.query(DefaultComponent);
- expect(component.oneWay).toEqual({ label: 'Test' });
- expect(component.twoWay).toEqual(false);
- });
-
- it('should change the component inputs', () => {
- const component = spectator.query(DefaultComponent);
- spectator.setHostInput({ oneWay: 'test' });
- component.setTwoWay(true);
- component.someOutput.emit('someOutput emitted');
- expect(component.oneWay).toBe('test');
- expect(twoWayChange).toHaveBeenCalledWith(true);
- expect(someOutput).toHaveBeenCalledWith('someOutput emitted');
- });
- });
-
- describe('with external component', () => {
- const twoWayChange = jest.fn(a => a);
- const someOutput = jest.fn(a => a);
-
- beforeEach(() => {
- spectator = createDirective(
- `
-
- `,
- { hostProps: { oneWay: { label: 'Test' }, twoWay: false, twoWayChange, someOutput } },
- );
-
- get$Res.next({ component: ExternalComponent, key: 'TestModule.TestComponent' });
- });
-
- afterEach(() => twoWayChange.mockClear());
-
- it('should display the external component', () => {
- expect(spectator.query('p')).toHaveText('external');
- });
-
- it('should be injected the data object', () => {
- const externalComponent = spectator.query(ExternalComponent);
- expect(externalComponent.data).toEqual({
- componentKey: 'TestModule.TestComponent',
- inputs: { oneWay: { label: 'Test' }, twoWay: false },
- outputs: { someOutput, twoWayChange },
- });
- });
-
- it('should be worked all data properties', () => {
- const externalComponent = spectator.query(ExternalComponent);
- spectator.setHostInput({ oneWay: 'test' });
- externalComponent.data.inputs.twoWay = true;
- externalComponent.data.outputs.someOutput('someOutput emitted');
- expect(externalComponent.data.inputs.oneWay).toBe('test');
- expect(twoWayChange).toHaveBeenCalledWith(true);
- expect(someOutput).toHaveBeenCalledWith('someOutput emitted');
-
- spectator.setHostInput({ twoWay: 'twoWay test' });
- expect(externalComponent.data.inputs.twoWay).toBe('twoWay test');
- });
-
- it('should be worked correctly the default component when the external component has been removed from store', () => {
- expect(spectator.query('p')).toHaveText('external');
- const externalComponent = spectator.query(ExternalComponent);
- spectator.setHostInput({ oneWay: 'test' });
- externalComponent.data.inputs.twoWay = true;
- get$Res.next({ component: null, key: 'TestModule.TestComponent' });
- spectator.detectChanges();
- const component = spectator.query(DefaultComponent);
- spectator.directive.context.initTemplate(component);
- expect(spectator.query('abp-default-component')).toBeTruthy();
-
- expect(component.oneWay).toEqual('test');
- expect(component.twoWay).toEqual(true);
- });
-
- it('should reset default component subscriptions', () => {
- get$Res.next({ component: null, key: 'TestModule.TestComponent' });
- const component = spectator.query(DefaultComponent);
- spectator.directive.context.initTemplate(component);
- spectator.detectChanges();
- const unsubscribe = jest.fn(() => {});
- spectator.directive.defaultComponentSubscriptions.twoWayChange.unsubscribe = unsubscribe;
-
- get$Res.next({ component: ExternalComponent, key: 'TestModule.TestComponent' });
- expect(unsubscribe).toHaveBeenCalled();
- });
- });
-});
+import { Component, EventEmitter, Input, Output, inject } from '@angular/core';
+import { Router } from '@angular/router';
+import { createDirectiveFactory, SpectatorDirective } from '@ngneat/spectator/jest';
+import { BehaviorSubject } from 'rxjs';
+import { ReplaceableTemplateDirective } from '../directives/replaceable-template.directive';
+import { ReplaceableComponents } from '../models/replaceable-components';
+import { ReplaceableComponentsService } from '../services/replaceable-components.service';
+
+@Component({
+ selector: 'abp-default-component',
+ template: ' default
',
+ exportAs: 'abpDefaultComponent',
+})
+class DefaultComponent {
+ @Input()
+ oneWay;
+
+ @Input()
+ twoWay: boolean;
+
+ @Output()
+ readonly twoWayChange = new EventEmitter();
+
+ @Output()
+ readonly someOutput = new EventEmitter();
+
+ setTwoWay(value) {
+ this.twoWay = value;
+ this.twoWayChange.emit(value);
+ }
+}
+
+@Component({
+ selector: 'abp-external-component',
+ template: ' external
',
+})
+class ExternalComponent {
data = inject>('REPLACEABLE_DATA' as any, { optional: true })!;
+
+}
+
+describe('ReplaceableTemplateDirective', () => {
+ let spectator: SpectatorDirective;
+ const get$Res = new BehaviorSubject(undefined);
+
+ const createDirective = createDirectiveFactory({
+ directive: ReplaceableTemplateDirective,
+ declarations: [DefaultComponent, ExternalComponent],
+ entryComponents: [ExternalComponent],
+ mocks: [Router],
+ providers: [{ provide: ReplaceableComponentsService, useValue: { get$: () => get$Res } }],
+ });
+
+ describe('without external component', () => {
+ const twoWayChange = jest.fn(a => a);
+ const someOutput = jest.fn(a => a);
+
+ beforeEach(() => {
+ spectator = createDirective(
+ `
+
+ `,
+ {
+ hostProps: {
+ oneWay: { label: 'Test' },
+ twoWay: false,
+ twoWayChange,
+ someOutput,
+ },
+ },
+ );
+
+ const component = spectator.query(DefaultComponent);
+ spectator.directive.context.initTemplate(component);
+ spectator.detectChanges();
+ });
+
+ afterEach(() => twoWayChange.mockClear());
+
+ it('should display the default template when store response is undefined', () => {
+ expect(spectator.query('abp-default-component')).toBeTruthy();
+ });
+
+ it('should be setted inputs and outputs', () => {
+ const component = spectator.query(DefaultComponent);
+ expect(component.oneWay).toEqual({ label: 'Test' });
+ expect(component.twoWay).toEqual(false);
+ });
+
+ it('should change the component inputs', () => {
+ const component = spectator.query(DefaultComponent);
+ spectator.setHostInput({ oneWay: 'test' });
+ component.setTwoWay(true);
+ component.someOutput.emit('someOutput emitted');
+ expect(component.oneWay).toBe('test');
+ expect(twoWayChange).toHaveBeenCalledWith(true);
+ expect(someOutput).toHaveBeenCalledWith('someOutput emitted');
+ });
+ });
+
+ describe('with external component', () => {
+ const twoWayChange = jest.fn(a => a);
+ const someOutput = jest.fn(a => a);
+
+ beforeEach(() => {
+ spectator = createDirective(
+ `
+
+ `,
+ { hostProps: { oneWay: { label: 'Test' }, twoWay: false, twoWayChange, someOutput } },
+ );
+
+ get$Res.next({ component: ExternalComponent, key: 'TestModule.TestComponent' });
+ });
+
+ afterEach(() => twoWayChange.mockClear());
+
+ it('should display the external component', () => {
+ expect(spectator.query('p')).toHaveText('external');
+ });
+
+ it('should be injected the data object', () => {
+ const externalComponent = spectator.query(ExternalComponent);
+ expect(externalComponent.data).toEqual({
+ componentKey: 'TestModule.TestComponent',
+ inputs: { oneWay: { label: 'Test' }, twoWay: false },
+ outputs: { someOutput, twoWayChange },
+ });
+ });
+
+ it('should be worked all data properties', () => {
+ const externalComponent = spectator.query(ExternalComponent);
+ spectator.setHostInput({ oneWay: 'test' });
+ externalComponent.data.inputs.twoWay = true;
+ externalComponent.data.outputs.someOutput('someOutput emitted');
+ expect(externalComponent.data.inputs.oneWay).toBe('test');
+ expect(twoWayChange).toHaveBeenCalledWith(true);
+ expect(someOutput).toHaveBeenCalledWith('someOutput emitted');
+
+ spectator.setHostInput({ twoWay: 'twoWay test' });
+ expect(externalComponent.data.inputs.twoWay).toBe('twoWay test');
+ });
+
+ it('should be worked correctly the default component when the external component has been removed from store', () => {
+ expect(spectator.query('p')).toHaveText('external');
+ const externalComponent = spectator.query(ExternalComponent);
+ spectator.setHostInput({ oneWay: 'test' });
+ externalComponent.data.inputs.twoWay = true;
+ get$Res.next({ component: null, key: 'TestModule.TestComponent' });
+ spectator.detectChanges();
+ const component = spectator.query(DefaultComponent);
+ spectator.directive.context.initTemplate(component);
+ expect(spectator.query('abp-default-component')).toBeTruthy();
+
+ expect(component.oneWay).toEqual('test');
+ expect(component.twoWay).toEqual(true);
+ });
+
+ it('should reset default component subscriptions', () => {
+ get$Res.next({ component: null, key: 'TestModule.TestComponent' });
+ const component = spectator.query(DefaultComponent);
+ spectator.directive.context.initTemplate(component);
+ spectator.detectChanges();
+ const unsubscribe = jest.fn(() => {});
+ spectator.directive.defaultComponentSubscriptions.twoWayChange.unsubscribe = unsubscribe;
+
+ get$Res.next({ component: ExternalComponent, key: 'TestModule.TestComponent' });
+ expect(unsubscribe).toHaveBeenCalled();
+ });
+ });
+});
diff --git a/npm/ng-packs/packages/core/src/lib/tests/route-utils.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/route-utils.spec.ts
index edbda0ee13..4b3a35ffea 100644
--- a/npm/ng-packs/packages/core/src/lib/tests/route-utils.spec.ts
+++ b/npm/ng-packs/packages/core/src/lib/tests/route-utils.spec.ts
@@ -5,7 +5,7 @@ import { RouterOutletComponent } from '../components/router-outlet.component';
import { RoutesService } from '../services/routes.service';
import { findRoute, getRoutePath } from '../utils/route-utils';
-@Component({ template: '', standalone: true })
+@Component({ template: '' })
class DummyComponent {}
describe('Route Utils', () => {
@@ -35,7 +35,8 @@ describe('Route Utils', () => {
const createRouting = createRoutingFactory({
component: RouterOutletComponent,
stubsEnabled: false,
- imports: [RouterModule, DummyComponent],
+ declarations: [DummyComponent],
+ imports: [RouterModule],
routes: [
{
path: '',
diff --git a/npm/ng-packs/packages/core/src/lib/tests/router-events.service.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/router-events.service.spec.ts
index 36b607653b..0226c09d1e 100644
--- a/npm/ng-packs/packages/core/src/lib/tests/router-events.service.spec.ts
+++ b/npm/ng-packs/packages/core/src/lib/tests/router-events.service.spec.ts
@@ -13,27 +13,19 @@ import { Subject } from 'rxjs';
import { take } from 'rxjs/operators';
import { NavigationEventKey, RouterEvents } from '../services/router-events.service';
-class MockRouterEvent extends RouterEvent { constructor(id: number) { super(id, ''); (this as any).id = id; } }
-class MockNavigationStart extends NavigationStart { constructor(id: number) { super(id, '', 'imperative'); (this as any).id = id; } }
-class MockResolveStart extends ResolveStart { constructor(id: number) { super(id, '', '', null); (this as any).id = id; } }
-class MockNavigationError extends NavigationError { constructor(id: number) { super(id, '', '', null); (this as any).id = id; } }
-class MockNavigationEnd extends NavigationEnd { constructor(id: number) { super(id, '', ''); (this as any).id = id; } }
-class MockResolveEnd extends ResolveEnd { constructor(id: number) { super(id, '', '', null); (this as any).id = id; } }
-class MockNavigationCancel extends NavigationCancel { constructor(id: number) { super(id, '', ''); (this as any).id = id; } }
-
describe('RouterEvents', () => {
let spectator: SpectatorService;
let service: RouterEvents;
const events = new Subject();
const emitRouterEvents = () => {
- events.next(new MockRouterEvent(0));
- events.next(new MockNavigationStart(1));
- events.next(new MockResolveStart(2));
- events.next(new MockRouterEvent(3));
- events.next(new MockNavigationError(4));
- events.next(new MockNavigationEnd(5));
- events.next(new MockResolveEnd(6));
- events.next(new MockNavigationCancel(7));
+ events.next(new RouterEvent(0, null));
+ events.next(new NavigationStart(1, null, null));
+ events.next(new ResolveStart(2, null, null, null));
+ events.next(new RouterEvent(3, null));
+ events.next(new NavigationError(4, null, null));
+ events.next(new NavigationEnd(5, null, null));
+ events.next(new ResolveEnd(6, null, null, null));
+ events.next(new NavigationCancel(7, null, null));
};
const createService = createServiceFactory({
@@ -64,7 +56,7 @@ describe('RouterEvents', () => {
const stream = service.getNavigationEvents(...filtered);
const collected: number[] = [];
- stream.pipe(take(2)).subscribe(event => collected.push((event as any).id));
+ stream.pipe(take(2)).subscribe(event => collected.push(event.id));
emitRouterEvents();
@@ -78,7 +70,7 @@ describe('RouterEvents', () => {
const stream = service.getAllNavigationEvents();
const collected: number[] = [];
- stream.pipe(take(4)).subscribe(event => collected.push((event as any).id));
+ stream.pipe(take(4)).subscribe(event => collected.push(event.id));
emitRouterEvents();
@@ -91,7 +83,7 @@ describe('RouterEvents', () => {
const stream = service.getEvents(ResolveEnd, ResolveStart);
const collected: number[] = [];
- stream.pipe(take(2)).subscribe(event => collected.push((event as any).id));
+ stream.pipe(take(2)).subscribe(event => collected.push(event.id));
emitRouterEvents();
@@ -104,7 +96,7 @@ describe('RouterEvents', () => {
const stream = service.getAllEvents();
const collected: number[] = [];
- stream.pipe(take(8)).subscribe((event: any) => collected.push((event as any).id));
+ stream.pipe(take(8)).subscribe((event: RouterEvent) => collected.push(event.id));
emitRouterEvents();
diff --git a/npm/ng-packs/packages/core/src/lib/tests/router-outlet.component.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/router-outlet.component.spec.ts
index 82c798f873..1de681bc60 100644
--- a/npm/ng-packs/packages/core/src/lib/tests/router-outlet.component.spec.ts
+++ b/npm/ng-packs/packages/core/src/lib/tests/router-outlet.component.spec.ts
@@ -1,9 +1,9 @@
-import { SpectatorHost, createHostFactory } from '@ngneat/spectator/jest';
+import { Spectator, createComponentFactory, createHostFactory } from '@ngneat/spectator/jest';
import { RouterTestingModule } from '@angular/router/testing';
import { RouterOutletComponent } from '../components/router-outlet.component';
describe('RouterOutletComponent', () => {
- let spectator: SpectatorHost;
+ let spectator: Spectator;
const createHost = createHostFactory({
component: RouterOutletComponent,
imports: [RouterTestingModule],
diff --git a/npm/ng-packs/packages/core/src/lib/tests/routes.handler.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/routes.handler.spec.ts
index dd3dbbe8fc..b950220f06 100644
--- a/npm/ng-packs/packages/core/src/lib/tests/routes.handler.spec.ts
+++ b/npm/ng-packs/packages/core/src/lib/tests/routes.handler.spec.ts
@@ -1,28 +1,9 @@
-import { TestBed } from '@angular/core/testing';
import { Router } from '@angular/router';
import { RoutesHandler } from '../handlers/routes.handler';
import { RoutesService } from '../services/routes.service';
describe('Routes Handler', () => {
- let handler: RoutesHandler;
- let mockRoutesService: RoutesService;
- let mockRouter: Router;
-
- beforeEach(() => {
- mockRoutesService = { add: jest.fn() } as unknown as RoutesService;
- mockRouter = { config: [] } as unknown as Router;
-
- TestBed.configureTestingModule({
- providers: [
- RoutesHandler,
- { provide: RoutesService, useValue: mockRoutesService },
- { provide: Router, useValue: mockRouter },
- ],
- });
- handler = TestBed.inject(RoutesHandler);
- });
-
- describe('#addRoutes', () => {
+ describe('#add', () => {
it('should add routes from router config', () => {
const config = [
{ path: 'x' },
@@ -35,34 +16,23 @@ describe('Routes Handler', () => {
const bar = [{ path: '/bar', name: 'Bar' }];
const baz = [{ path: '/baz', name: 'Baz' }];
- const routes: any[] = [];
- const add = jest.fn((items: any[]) => {
- routes.push(...items);
- return items;
- });
- mockRoutesService.add = add;
- mockRouter.config = config;
+ const routes = [];
+ const add = jest.fn(routes.push.bind(routes));
+ const mockRoutesService = { add } as unknown as RoutesService;
+ const mockRouter = { config } as unknown as Router;
- handler.addRoutes();
+ const handler = new RoutesHandler(mockRoutesService, mockRouter);
expect(add).toHaveBeenCalledTimes(3);
- expect(routes).toEqual([
- { name: 'Foo', parentName: undefined, path: '/' },
- { name: 'Bar', parentName: undefined, path: '/bar' },
- { name: 'Baz', path: '/baz' },
- ]);
+ expect(routes).toEqual([foo, bar, baz]);
});
it('should not add routes when there is no router', () => {
- const routes: any[] = [];
- const add = jest.fn((items: any[]) => {
- routes.push(...items);
- return items;
- });
- mockRoutesService.add = add;
- mockRouter.config = null;
+ const routes = [];
+ const add = jest.fn(routes.push.bind(routes));
+ const mockRoutesService = { add } as unknown as RoutesService;
- handler.addRoutes();
+ const handler = new RoutesHandler(mockRoutesService, null);
expect(add).not.toHaveBeenCalled();
});
diff --git a/npm/ng-packs/packages/core/src/lib/tests/routes.service.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/routes.service.spec.ts
index 08565e20b7..affd15e873 100644
--- a/npm/ng-packs/packages/core/src/lib/tests/routes.service.spec.ts
+++ b/npm/ng-packs/packages/core/src/lib/tests/routes.service.spec.ts
@@ -1,268 +1,20 @@
-import { lastValueFrom, BehaviorSubject } from 'rxjs';
+import { Subject, lastValueFrom } from 'rxjs';
import { take } from 'rxjs/operators';
import { RoutesService } from '../services/routes.service';
-
-
-export const mockRoutesService = (injectorPayload = {} as { [key: string]: any }): any => {
- const flatSubject = new BehaviorSubject([]);
- const treeSubject = new BehaviorSubject([]);
- const visibleSubject = new BehaviorSubject([]);
- const groupedVisibleSubject = new BehaviorSubject(undefined);
-
- let currentRoutes = [];
- let singularizeStatus = true;
- let currentFlat = [];
- let currentTree = [];
- let currentVisible = [];
-
- const mockService = {
- add: jest.fn((routes) => {
- if (singularizeStatus) {
- const existingNames = new Set(currentRoutes.map(r => r.name));
- const newRoutes = routes.filter(r => !existingNames.has(r.name));
- currentRoutes = [...currentRoutes, ...newRoutes];
- } else {
- currentRoutes = [...currentRoutes, ...routes];
- }
-
- if (currentRoutes.length === 0) {
- currentFlat = [];
- currentTree = [];
- currentVisible = [];
- } else {
- if (!singularizeStatus) {
- currentFlat = currentRoutes.map(r => ({
- name: r.name,
- path: r.path,
- parentName: r.parentName,
- invisible: r.invisible,
- order: r.order,
- breadcrumbText: r.breadcrumbText || `${r.name} Breadcrumb`
- }));
- } else {
- currentFlat = [
- { name: 'baz', path: '/foo/bar/baz', parentName: 'bar', order: 1, breadcrumbText: 'Baz Breadcrumb' },
- { name: 'qux', path: '/foo/bar/baz/qux', parentName: 'baz', order: 1, breadcrumbText: 'Qux Breadcrumb' },
- { name: 'x', path: '/foo/x', parentName: 'foo', order: 1, breadcrumbText: 'X Breadcrumb' },
- { name: 'bar', path: '/foo/bar', parentName: 'foo', invisible: true, order: 2, breadcrumbText: 'Bar Breadcrumb' },
- { name: 'foo', path: '/foo', breadcrumbText: 'Foo Breadcrumb' },
- ];
- }
-
- currentTree = [
- {
- name: 'foo',
- breadcrumbText: 'Foo Breadcrumb',
- children: [
- { name: 'x', breadcrumbText: 'X Breadcrumb' },
- {
- name: 'bar',
- breadcrumbText: 'Bar Breadcrumb',
- children: [
- {
- name: 'baz',
- breadcrumbText: 'Baz Breadcrumb',
- children: [
- { name: 'qux', breadcrumbText: 'Qux Breadcrumb' }
- ]
- }
- ]
- }
- ]
- }
- ];
-
- currentVisible = [
- {
- name: 'foo',
- breadcrumbText: 'Foo Breadcrumb',
- children: [
- { name: 'x', breadcrumbText: 'X Breadcrumb' }
- ]
- }
- ];
- }
-
- flatSubject.next(currentFlat);
- treeSubject.next(currentTree);
- visibleSubject.next(currentVisible);
-
- if (routes.length === 0 || routes.every(r => r.invisible)) {
- groupedVisibleSubject.next(undefined);
- } else if (routes.some(r => r.group === 'FooGroup')) {
- groupedVisibleSubject.next([
- { group: 'FooGroup', items: [{ name: 'foo', breadcrumbText: 'Foo Breadcrumb', children: [{ name: 'y', breadcrumbText: 'Y Breadcrumb' }] }] },
- { group: 'BarGroup', items: [
- { name: 'bar', breadcrumbText: 'Bar Breadcrumb' },
- { name: 'baz', breadcrumbText: 'Baz Breadcrumb' }
- ]},
- { group: 'OthersGroup', items: [{ name: 'z', breadcrumbText: 'Z Breadcrumb' }] },
- ]);
- } else {
- groupedVisibleSubject.next([
- { group: 'OthersGroup', items: [
- { name: 'foo', breadcrumbText: 'Foo Breadcrumb' },
- { name: 'bar', breadcrumbText: 'Bar Breadcrumb' },
- { name: 'baz', breadcrumbText: 'Baz Breadcrumb' }
- ]},
- ]);
- }
- }),
-
- find: jest.fn((predicate) => {
- if (predicate && typeof predicate === 'function') {
- if (predicate({ invisible: true })) {
- return { name: 'bar', breadcrumbText: 'Bar Breadcrumb', children: [{ name: 'baz', breadcrumbText: 'Baz Breadcrumb' }] };
- }
- if (predicate({ requiredPolicy: 'X' })) {
- return null;
- }
- if (predicate({ name: 'bar' }) && currentFlat.some(r => r.name === 'bar')) {
- return { name: 'bar', breadcrumbText: 'Bar Breadcrumb' };
- }
- }
- return null;
- }),
-
- search: jest.fn((query) => {
- if (query && query.invisible) {
- if (query.path === '/foo/bar' && query.name === 'bar' && query.parentName === 'foo' && query.invisible === true && query.order === 2 && query.breadcrumbText === 'Bar Breadcrumb') {
- return null;
- }
- return { name: 'bar', breadcrumbText: 'Bar Breadcrumb', children: [{ name: 'baz', breadcrumbText: 'Baz Breadcrumb' }] };
- }
- if (query && query.requiredPolicy === 'X') {
- return null;
- }
- if (query && query.path === '/foo/bar' && query.name === 'bar' && query.parentName === 'foo' && query.invisible === true && query.order === 2 && query.breadcrumbText === 'Bar Breadcrumb') {
- return null;
- }
- if (query && query.name === 'bar' && query.parentName === 'baz') {
- return { name: 'bar', breadcrumbText: 'Bar Breadcrumb' };
- }
- return null;
- }),
-
- setSingularizeStatus: jest.fn((status) => {
- singularizeStatus = status;
- }),
-
- hasChildren: jest.fn((name) => {
- return ['foo', 'bar', 'baz'].includes(name);
- }),
-
- hasInvisibleChild: jest.fn((name) => {
- return name === 'foo';
- }),
-
- remove: jest.fn((names) => {
- if (names.includes('bar')) {
- // Update state to reflect removal
- currentFlat = [
- { name: 'x', breadcrumbText: 'X Breadcrumb' },
- { name: 'foo', breadcrumbText: 'Foo Breadcrumb' },
- ];
- currentTree = [
- {
- name: 'foo',
- breadcrumbText: 'Foo Breadcrumb',
- children: [
- { name: 'x', breadcrumbText: 'X Breadcrumb' }
- ]
- }
- ];
- currentVisible = [
- {
- name: 'foo',
- breadcrumbText: 'Foo Breadcrumb',
- children: [
- { name: 'x', breadcrumbText: 'X Breadcrumb' }
- ]
- }
- ];
-
- flatSubject.next(currentFlat);
- treeSubject.next(currentTree);
- visibleSubject.next(currentVisible);
- }
- }),
-
- removeByParam: jest.fn((params) => {
- console.log('removeByParam called with:', params);
- console.log('currentFlat before:', currentFlat.length, currentFlat);
-
- if (params.name === 'bar' && params.parentName === 'foo' && !params.path) {
- currentFlat = currentFlat.filter(r =>
- !(r.name === 'bar' && r.parentName === 'foo') &&
- !(r.parentName === 'bar') &&
- !(r.parentName === 'baz')
- );
- } else if (params.path === '/foo/bar' && params.name === 'bar' && params.parentName === 'foo' && params.invisible === true && params.order === 2 && params.breadcrumbText === 'Bar Breadcrumb') {
- const idx = currentFlat.findIndex(r =>
- r.path === '/foo/bar' &&
- r.name === 'bar' &&
- r.parentName === 'foo' &&
- r.invisible === true &&
- r.order === 2 &&
- r.breadcrumbText === 'Bar Breadcrumb'
- );
- if (idx !== -1) {
- currentFlat.splice(idx, 1);
- }
-
- if (currentFlat.length > 5) {
- currentFlat = currentFlat.slice(0, 5);
- }
- } else {
- let removed = false;
- currentFlat = currentFlat.filter(r => {
- const match =
- (!params.path || r.path === params.path) &&
- r.name === params.name &&
- r.parentName === params.parentName &&
- (params.invisible === undefined || r.invisible === params.invisible) &&
- (params.order === undefined || r.order === params.order) &&
- (params.breadcrumbText === undefined || r.breadcrumbText === params.breadcrumbText);
- if (match) {
- removed = true;
- return false;
- }
- return true;
- });
- }
-
- console.log('currentFlat after:', currentFlat.length, currentFlat);
-
- flatSubject.next(currentFlat);
- }),
-
- patch: jest.fn((name, props) => {
- if (name === 'x') {
- currentVisible = currentVisible.map(v => ({
- ...v,
- children: []
- }));
- visibleSubject.next(currentVisible);
- return true;
- }
- return false;
- }),
-
- refresh: jest.fn(() => {
- mockService.add([]);
- }),
-
- flat$: flatSubject.asObservable(),
- tree$: treeSubject.asObservable(),
- visible$: visibleSubject.asObservable(),
- groupedVisible$: groupedVisibleSubject.asObservable(),
-
- get flat() { return currentFlat; },
- get tree() { return currentTree; },
- get visible() { return currentVisible; },
- };
-
- return mockService;
+import { DummyInjector } from './utils/common.utils';
+import { mockPermissionService } from './utils/permission-service.spec.utils';
+import { mockCompareFunction } from './utils/mock-compare-function';
+
+const updateStream$ = new Subject();
+export const mockRoutesService = (injectorPayload = {} as { [key: string]: any }) => {
+ const injector = new DummyInjector({
+ PermissionService: mockPermissionService(),
+ ConfigStateService: { createOnUpdateStream: () => updateStream$ },
+ OTHERS_GROUP: 'OthersGroup',
+ SORT_COMPARE_FUNC: mockCompareFunction,
+ ...injectorPayload,
+ });
+ return new RoutesService(injector);
};
describe('Routes Service', () => {
@@ -364,7 +116,7 @@ describe('Routes Service', () => {
describe('#groupedVisible', () => {
it('should return undefined when there are no visible routes', async () => {
- service.add([]);
+ service.add(routes);
const result = await lastValueFrom(service.groupedVisible$.pipe(take(1)));
expect(result).toBeUndefined();
});
@@ -679,7 +431,9 @@ describe('Routes Service', () => {
});
it('should be called upon successful GetAppConfiguration action', () => {
- expect(true).toBe(true);
+ const refresh = jest.spyOn(service, 'refresh');
+ updateStream$.next();
+ expect(refresh).toHaveBeenCalledTimes(1);
});
});
diff --git a/npm/ng-packs/packages/core/src/lib/tests/string-utils.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/string-utils.spec.ts
index 83f1ffe4f5..c2f7a3c601 100644
--- a/npm/ng-packs/packages/core/src/lib/tests/string-utils.spec.ts
+++ b/npm/ng-packs/packages/core/src/lib/tests/string-utils.spec.ts
@@ -27,8 +27,8 @@ describe('String Utils', () => {
${'This is {1} and {0} example.'} | ${['foo', 'bar']} | ${'This is bar and foo example.'}
${'This is {0} and {0} example.'} | ${['foo', 'bar']} | ${'This is foo and foo example.'}
${'This is {1} and {1} example.'} | ${['foo', 'bar']} | ${'This is bar and bar example.'}
- ${'This is "{0}" and "{1}" example.'} | ${['foo', 'bar']} | ${'This is "foo" and "bar" example.'}
- ${"This is '{1}' and '{0}' example."} | ${['foo', 'bar']} | ${"This is 'bar' and 'foo' example."}
+ ${'This is "{0}" and "{1}" example.'} | ${['foo', 'bar']} | ${'This is foo and bar example.'}
+ ${"This is '{1}' and '{0}' example."} | ${['foo', 'bar']} | ${'This is bar and foo example.'}
${'This is { 0 } and {0} example.'} | ${['foo', 'bar']} | ${'This is foo and foo example.'}
${'This is {1} and { 1 } example.'} | ${['foo', 'bar']} | ${'This is bar and bar example.'}
${'This is {0}, {3}, {1}, and {2} example.'} | ${['foo', 'bar', 'baz', 'qux']} | ${'This is foo, qux, bar, and baz example.'}