Browse Source

update: core package tests

pull/24530/head
sumeyye 2 weeks ago
parent
commit
6cc24f3f71
  1. 6
      npm/ng-packs/packages/core/src/lib/tests/autofocus.directive.spec.ts
  2. 68
      npm/ng-packs/packages/core/src/lib/tests/capsLock.directive.spec.ts
  3. 2
      npm/ng-packs/packages/core/src/lib/tests/config-state.service.spec.ts
  4. 3
      npm/ng-packs/packages/core/src/lib/tests/content-projection.service.spec.ts
  5. 44
      npm/ng-packs/packages/core/src/lib/tests/content.strategy.spec.ts
  6. 10
      npm/ng-packs/packages/core/src/lib/tests/debounce.directive.spec.ts
  7. 19
      npm/ng-packs/packages/core/src/lib/tests/dom-insertion.service.spec.ts
  8. 27
      npm/ng-packs/packages/core/src/lib/tests/dom.strategy.spec.ts
  9. 11
      npm/ng-packs/packages/core/src/lib/tests/dynamic-layout.component.spec.ts
  10. 23
      npm/ng-packs/packages/core/src/lib/tests/environment.service.spec.ts
  11. 33
      npm/ng-packs/packages/core/src/lib/tests/for.directive.spec.ts
  12. 17
      npm/ng-packs/packages/core/src/lib/tests/form-submit.directive.spec.ts
  13. 10
      npm/ng-packs/packages/core/src/lib/tests/initial-utils.spec.ts
  14. 1
      npm/ng-packs/packages/core/src/lib/tests/internal-store.spec.ts
  15. 107
      npm/ng-packs/packages/core/src/lib/tests/internet-connection.service.spec.ts
  16. 2
      npm/ng-packs/packages/core/src/lib/tests/lazy-load.service.spec.ts
  17. 116
      npm/ng-packs/packages/core/src/lib/tests/list.service.spec.ts
  18. 36
      npm/ng-packs/packages/core/src/lib/tests/loading.strategy.spec.ts
  19. 17
      npm/ng-packs/packages/core/src/lib/tests/multi-tenancy-utils.spec.ts
  20. 35
      npm/ng-packs/packages/core/src/lib/tests/permission.directive.spec.ts
  21. 43
      npm/ng-packs/packages/core/src/lib/tests/permission.guard.spec.ts
  22. 23
      npm/ng-packs/packages/core/src/lib/tests/projection.strategy.spec.ts
  23. 15
      npm/ng-packs/packages/core/src/lib/tests/rest.service.spec.ts
  24. 84
      npm/ng-packs/packages/core/src/lib/tests/show-password-directive.spec.ts
  25. 3
      npm/ng-packs/packages/core/src/lib/tests/stop-propagation.directive.spec.ts
  26. 11
      npm/ng-packs/packages/core/src/test-setup.ts

6
npm/ng-packs/packages/core/src/lib/tests/autofocus.directive.spec.ts

@ -1,6 +1,6 @@
import { createDirectiveFactory, SpectatorDirective } from '@ngneat/spectator/vitest'; import { createDirectiveFactory, SpectatorDirective } from '@ngneat/spectator/vitest';
import { AutofocusDirective } from '../directives/autofocus.directive'; import { AutofocusDirective } from '../directives/autofocus.directive';
import { timer , firstValueFrom } from 'rxjs'; import { timer } from 'rxjs';
describe('AutofocusDirective', () => { describe('AutofocusDirective', () => {
let spectator: SpectatorDirective<AutofocusDirective>; let spectator: SpectatorDirective<AutofocusDirective>;
@ -26,11 +26,11 @@ describe('AutofocusDirective', () => {
expect(directive.delay).toBe(10); expect(directive.delay).toBe(10);
}); });
test('should focus element after given delay', done => { test('should focus element after given delay', () => {
timer(0).subscribe(() => expect('input').not.toBeFocused()); timer(0).subscribe(() => expect('input').not.toBeFocused());
timer(11).subscribe(() => { timer(11).subscribe(() => {
expect('input').toBeFocused(); expect('input').toBeFocused();
done(); expect.hasAssertions();
}); });
}); });
}); });

68
npm/ng-packs/packages/core/src/lib/tests/capsLock.directive.spec.ts

@ -1,26 +1,23 @@
import { Component, DebugElement } from '@angular/core'
import { ComponentFixture, TestBed } from '@angular/core/testing'
import { TrackCapsLockDirective } from '../directives';
import { By } from '@angular/platform-browser'; import { By } from '@angular/platform-browser';
import { Component, DebugElement } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { TrackCapsLockDirective } from '../directives';
@Component({ @Component({
standalone:true, template: ` <input (abpCapsLock)="capsLock = $event" /> `,
template: ` imports: [TrackCapsLockDirective],
<input (abpCapsLock)="capsLock = $event" />
`,
imports:[TrackCapsLockDirective]
}) })
class TestComponent { class TestComponent {
capsLock = false capsLock = false;
} }
describe('TrackCapsLockDirective',()=>{ describe('TrackCapsLockDirective', () => {
let fixture: ComponentFixture<TestComponent>;; let fixture: ComponentFixture<TestComponent>;
let des : DebugElement[]; let des: DebugElement[];
beforeEach(()=>{ beforeEach(() => {
fixture = TestBed.configureTestingModule({ fixture = TestBed.configureTestingModule({
imports: [ TestComponent ] imports: [TestComponent],
}).createComponent(TestComponent); }).createComponent(TestComponent);
fixture.detectChanges(); fixture.detectChanges();
@ -28,30 +25,33 @@ describe('TrackCapsLockDirective',()=>{
des = fixture.debugElement.queryAll(By.directive(TrackCapsLockDirective)); des = fixture.debugElement.queryAll(By.directive(TrackCapsLockDirective));
}); });
test.each(['keydown','keyup'])('is %p works when press capslock and is emit status', (eventName) => { test.each(['keydown', 'keyup'])(
'is %p works when press capslock and is emit status',
eventName => {
const event = new KeyboardEvent(eventName, { const event = new KeyboardEvent(eventName, {
key: 'CapsLock', key: 'CapsLock',
modifierCapsLock: true modifierCapsLock: true,
}); });
window.dispatchEvent(event); window.dispatchEvent(event);
fixture.detectChanges(); fixture.detectChanges();
expect(fixture.componentInstance.capsLock).toBe(true) expect(fixture.componentInstance.capsLock).toBe(true);
}); },
);
test.each(['keydown','keyup'])('is %p detect the change capslock is emit status', (eventName) => { test.each(['keydown', 'keyup'])('is %p detect the change capslock is emit status', eventName => {
const trueEvent = new KeyboardEvent(eventName, { const trueEvent = new KeyboardEvent(eventName, {
key: 'CapsLock', key: 'CapsLock',
modifierCapsLock: true modifierCapsLock: true,
}); });
window.dispatchEvent(trueEvent); window.dispatchEvent(trueEvent);
fixture.detectChanges(); fixture.detectChanges();
expect(fixture.componentInstance.capsLock).toBe(true) expect(fixture.componentInstance.capsLock).toBe(true);
const falseEvent = new KeyboardEvent(eventName, { const falseEvent = new KeyboardEvent(eventName, {
key: 'CapsLock', key: 'CapsLock',
modifierCapsLock: false modifierCapsLock: false,
});
window.dispatchEvent(falseEvent);
fixture.detectChanges();
expect(fixture.componentInstance.capsLock).toBe(false)
}); });
}); window.dispatchEvent(falseEvent);
fixture.detectChanges();
expect(fixture.componentInstance.capsLock).toBe(false);
});
});

2
npm/ng-packs/packages/core/src/lib/tests/config-state.service.spec.ts

@ -132,7 +132,7 @@ describe('ConfigStateService', () => {
}, },
{ {
provide: AbpApplicationLocalizationService, provide: AbpApplicationLocalizationService,
useValue: { get: () => APPLICATION_LOCALIZATION_DATA }, useValue: { get: () => of(APPLICATION_LOCALIZATION_DATA) },
}, },
IncludeLocalizationResourcesProvider, IncludeLocalizationResourcesProvider,
], ],

3
npm/ng-packs/packages/core/src/lib/tests/content-projection.service.spec.ts

@ -1,10 +1,9 @@
import { Component, ComponentRef } from '@angular/core'; import { Component, ComponentRef } from '@angular/core';
import { createServiceFactory, SpectatorService } from '@ngneat/spectator/vitest'; import { createServiceFactory, SpectatorService } from '@ngneat/spectator/vitest';
import { ContentProjectionService } from '../services'; import { ContentProjectionService } from '../services';
import { PROJECTION_STRATEGY } from '../strategies';
describe('ContentProjectionService', () => { describe('ContentProjectionService', () => {
@Component({ @Component({
template: '<div class="foo">bar</div>', template: '<div class="foo">bar</div>',
}) })
class TestComponent {} class TestComponent {}

44
npm/ng-packs/packages/core/src/lib/tests/content.strategy.spec.ts

@ -1,3 +1,5 @@
import { Injector, runInInjectionContext } from '@angular/core';
import { TestBed } from '@angular/core/testing';
import { import {
CONTENT_SECURITY_STRATEGY, CONTENT_SECURITY_STRATEGY,
CONTENT_STRATEGY, CONTENT_STRATEGY,
@ -8,10 +10,17 @@ import {
import { uuid } from '../utils'; import { uuid } from '../utils';
describe('StyleContentStrategy', () => { describe('StyleContentStrategy', () => {
let injector: Injector;
beforeEach(() => {
TestBed.configureTestingModule({});
injector = TestBed.inject(Injector);
});
describe('#createElement', () => { describe('#createElement', () => {
it('should create a style element', () => { it('should create a style element', () => {
const strategy = new StyleContentStrategy(''); const strategy = new StyleContentStrategy('');
const element = strategy.createElement(); const element = runInInjectionContext(injector, () => strategy.createElement());
expect(element.tagName).toBe('STYLE'); expect(element.tagName).toBe('STYLE');
}); });
@ -26,8 +35,8 @@ describe('StyleContentStrategy', () => {
domStrategy.insertElement = vi.fn((el: HTMLScriptElement) => {}) as any; domStrategy.insertElement = vi.fn((el: HTMLScriptElement) => {}) as any;
const strategy = new StyleContentStrategy('', domStrategy, contentSecurityStrategy); const strategy = new StyleContentStrategy('', domStrategy, contentSecurityStrategy);
strategy.createElement(); runInInjectionContext(injector, () => strategy.createElement());
const element = strategy.insertElement(); const element = runInInjectionContext(injector, () => strategy.insertElement());
expect(contentSecurityStrategy.applyCSP).toHaveBeenCalledWith(element); expect(contentSecurityStrategy.applyCSP).toHaveBeenCalledWith(element);
expect(domStrategy.insertElement).toHaveBeenCalledWith(element); expect(domStrategy.insertElement).toHaveBeenCalledWith(element);
@ -36,11 +45,17 @@ describe('StyleContentStrategy', () => {
}); });
describe('ScriptContentStrategy', () => { describe('ScriptContentStrategy', () => {
let injector: Injector;
beforeEach(() => {
TestBed.configureTestingModule({});
injector = TestBed.inject(Injector);
});
describe('#createElement', () => { describe('#createElement', () => {
it('should create a style element', () => { it('should create a script element', () => {
const nonce = uuid();
const strategy = new ScriptContentStrategy(''); const strategy = new ScriptContentStrategy('');
const element = strategy.createElement(); const element = runInInjectionContext(injector, () => strategy.createElement());
expect(element.tagName).toBe('SCRIPT'); expect(element.tagName).toBe('SCRIPT');
}); });
@ -49,7 +64,6 @@ describe('ScriptContentStrategy', () => {
describe('#insertElement', () => { describe('#insertElement', () => {
it('should use given dom and content security strategies', () => { it('should use given dom and content security strategies', () => {
const nonce = uuid(); const nonce = uuid();
const domStrategy = DOM_STRATEGY.PrependToHead(); const domStrategy = DOM_STRATEGY.PrependToHead();
const contentSecurityStrategy = CONTENT_SECURITY_STRATEGY.Loose(nonce); const contentSecurityStrategy = CONTENT_SECURITY_STRATEGY.Loose(nonce);
@ -57,8 +71,8 @@ describe('ScriptContentStrategy', () => {
domStrategy.insertElement = vi.fn((el: HTMLScriptElement) => {}) as any; domStrategy.insertElement = vi.fn((el: HTMLScriptElement) => {}) as any;
const strategy = new ScriptContentStrategy('', domStrategy, contentSecurityStrategy); const strategy = new ScriptContentStrategy('', domStrategy, contentSecurityStrategy);
const element = strategy.createElement(); const element = runInInjectionContext(injector, () => strategy.createElement());
strategy.insertElement(); runInInjectionContext(injector, () => strategy.insertElement());
expect(contentSecurityStrategy.applyCSP).toHaveBeenCalledWith(element); expect(contentSecurityStrategy.applyCSP).toHaveBeenCalledWith(element);
expect(domStrategy.insertElement).toHaveBeenCalledWith(element); expect(domStrategy.insertElement).toHaveBeenCalledWith(element);
@ -67,6 +81,10 @@ describe('ScriptContentStrategy', () => {
}); });
describe('CONTENT_STRATEGY', () => { describe('CONTENT_STRATEGY', () => {
beforeEach(() => {
TestBed.configureTestingModule({});
});
test.each` test.each`
name | Strategy | domStrategy name | Strategy | domStrategy
${'AppendScriptToBody'} | ${ScriptContentStrategy} | ${'AppendToBody'} ${'AppendScriptToBody'} | ${ScriptContentStrategy} | ${'AppendToBody'}
@ -76,7 +94,13 @@ describe('CONTENT_STRATEGY', () => {
`( `(
'should successfully map $name to $Strategy.name with $domStrategy dom strategy', 'should successfully map $name to $Strategy.name with $domStrategy dom strategy',
({ name, Strategy, domStrategy }) => { ({ name, Strategy, domStrategy }) => {
expect(CONTENT_STRATEGY[name]('')).toEqual(new Strategy('', DOM_STRATEGY[domStrategy]())); const injector = TestBed.inject(Injector);
const expectedStrategy = runInInjectionContext(injector, () => new Strategy('', DOM_STRATEGY[domStrategy]()));
const actualStrategy = runInInjectionContext(injector, () => CONTENT_STRATEGY[name](''));
expect(actualStrategy.constructor).toBe(expectedStrategy.constructor);
expect(actualStrategy.content).toBe(expectedStrategy.content);
expect(actualStrategy['domStrategy'].constructor).toBe(expectedStrategy['domStrategy'].constructor);
}, },
); );
}); });

10
npm/ng-packs/packages/core/src/lib/tests/debounce.directive.spec.ts

@ -1,6 +1,6 @@
import { timer , firstValueFrom } from 'rxjs';
import { createDirectiveFactory, SpectatorDirective } from '@ngneat/spectator/vitest'; import { createDirectiveFactory, SpectatorDirective } from '@ngneat/spectator/vitest';
import { InputEventDebounceDirective } from '../directives/debounce.directive'; import { InputEventDebounceDirective } from '../directives/debounce.directive';
import { timer , firstValueFrom } from 'rxjs';
describe('InputEventDebounceDirective', () => { describe('InputEventDebounceDirective', () => {
let spectator: SpectatorDirective<InputEventDebounceDirective>; let spectator: SpectatorDirective<InputEventDebounceDirective>;
@ -29,12 +29,10 @@ describe('InputEventDebounceDirective', () => {
expect(directive.debounce).toBe(20); expect(directive.debounce).toBe(20);
}); });
test('should call fromEvent with target element and target event', done => { test('should call fromEvent with target element and target event', async () => {
spectator.dispatchFakeEvent('input', 'input', true); spectator.dispatchFakeEvent('input', 'input', true);
timer(0).subscribe(() => expect(inputEventFn).not.toHaveBeenCalled()); timer(0).subscribe(() => expect(inputEventFn).not.toHaveBeenCalled());
timer(21).subscribe(() => { await firstValueFrom(timer(21));
expect(inputEventFn).toHaveBeenCalled(); expect(inputEventFn).toHaveBeenCalled();
done();
});
}); });
}); });

19
npm/ng-packs/packages/core/src/lib/tests/dom-insertion.service.spec.ts

@ -1,3 +1,4 @@
import { Injector, runInInjectionContext } from '@angular/core';
import { createServiceFactory, SpectatorService } from '@ngneat/spectator'; import { createServiceFactory, SpectatorService } from '@ngneat/spectator';
import { DomInsertionService } from '../services'; import { DomInsertionService } from '../services';
import { CONTENT_STRATEGY } from '../strategies'; import { CONTENT_STRATEGY } from '../strategies';
@ -14,28 +15,30 @@ describe('DomInsertionService', () => {
describe('#insertContent', () => { describe('#insertContent', () => {
it('should be able to insert given content', () => { it('should be able to insert given content', () => {
spectator.service.insertContent(CONTENT_STRATEGY.AppendStyleToHead(content)); const injector = spectator.inject(Injector);
runInInjectionContext(injector, () => spectator.service.insertContent(CONTENT_STRATEGY.AppendStyleToHead(content)));
styleElements = document.head.querySelectorAll('style'); styleElements = document.head.querySelectorAll('style');
expect(styleElements.length).toBe(1); expect(styleElements.length).toBe(1);
expect(styleElements[0].textContent).toBe(content); expect(styleElements[0].textContent).toBe(content);
}); });
it('should set a hash for the inserted content', () => { it('should set a hash for the inserted content', () => {
spectator.service.insertContent(CONTENT_STRATEGY.AppendStyleToHead(content)); const injector = spectator.inject(Injector);
runInInjectionContext(injector, () => spectator.service.insertContent(CONTENT_STRATEGY.AppendStyleToHead(content)));
expect(spectator.service.has(content)).toBe(true); expect(spectator.service.has(content)).toBe(true);
}); });
it('should insert only once', () => { it('should insert only once', () => {
expect(spectator.service.has(content)).toBe(false); expect(spectator.service.has(content)).toBe(false);
const injector = spectator.inject(Injector);
spectator.service.insertContent(CONTENT_STRATEGY.AppendStyleToHead(content)); runInInjectionContext(injector, () => spectator.service.insertContent(CONTENT_STRATEGY.AppendStyleToHead(content)));
styleElements = document.head.querySelectorAll('style'); styleElements = document.head.querySelectorAll('style');
expect(styleElements.length).toBe(1); expect(styleElements.length).toBe(1);
expect(styleElements[0].textContent).toBe(content); expect(styleElements[0].textContent).toBe(content);
expect(spectator.service.has(content)).toBe(true); expect(spectator.service.has(content)).toBe(true);
spectator.service.insertContent(CONTENT_STRATEGY.AppendStyleToHead(content)); runInInjectionContext(injector, () => spectator.service.insertContent(CONTENT_STRATEGY.AppendStyleToHead(content)));
styleElements = document.head.querySelectorAll('style'); styleElements = document.head.querySelectorAll('style');
expect(styleElements.length).toBe(1); expect(styleElements.length).toBe(1);
@ -44,7 +47,8 @@ describe('DomInsertionService', () => {
}); });
it('should return inserted element', () => { it('should return inserted element', () => {
const element = spectator.service.insertContent(CONTENT_STRATEGY.AppendStyleToHead(content)); const injector = spectator.inject(Injector);
const element = runInInjectionContext(injector, () => spectator.service.insertContent(CONTENT_STRATEGY.AppendStyleToHead(content)));
expect(element.tagName).toBe('STYLE'); expect(element.tagName).toBe('STYLE');
}); });
}); });
@ -52,7 +56,8 @@ describe('DomInsertionService', () => {
describe('#removeContent', () => { describe('#removeContent', () => {
it('should remove inserted element and the hash for the content', () => { it('should remove inserted element and the hash for the content', () => {
expect(document.head.querySelector('style')).toBeNull(); expect(document.head.querySelector('style')).toBeNull();
const element = spectator.service.insertContent(CONTENT_STRATEGY.AppendStyleToHead(content)); const injector = spectator.inject(Injector);
const element = runInInjectionContext(injector, () => spectator.service.insertContent(CONTENT_STRATEGY.AppendStyleToHead(content)));
expect(spectator.service.has(content)).toBe(true); expect(spectator.service.has(content)).toBe(true);
spectator.service.removeContent(element); spectator.service.removeContent(element);

27
npm/ng-packs/packages/core/src/lib/tests/dom.strategy.spec.ts

@ -3,7 +3,7 @@ import { DOM_STRATEGY, DomStrategy } from '../strategies/dom.strategy';
describe('DomStrategy', () => { describe('DomStrategy', () => {
describe('#insertElement', () => { describe('#insertElement', () => {
it('should append element to head by default', () => { it('should append element to head by default', () => {
const strategy = new DomStrategy(); const strategy = new DomStrategy(() => document.head);
const element = document.createElement('script'); const element = document.createElement('script');
strategy.insertElement(element); strategy.insertElement(element);
@ -11,7 +11,7 @@ describe('DomStrategy', () => {
}); });
it('should append element to body when body is given as target', () => { it('should append element to body when body is given as target', () => {
const strategy = new DomStrategy(document.body); const strategy = new DomStrategy(() => document.body);
const element = document.createElement('script'); const element = document.createElement('script');
strategy.insertElement(element); strategy.insertElement(element);
@ -19,7 +19,7 @@ describe('DomStrategy', () => {
}); });
it('should prepend to head when position is given as "afterbegin"', () => { it('should prepend to head when position is given as "afterbegin"', () => {
const strategy = new DomStrategy(undefined, 'afterbegin'); const strategy = new DomStrategy(() => document.head, 'afterbegin');
const element = document.createElement('script'); const element = document.createElement('script');
strategy.insertElement(element); strategy.insertElement(element);
@ -37,13 +37,18 @@ describe('DOM_STRATEGY', () => {
}); });
test.each` test.each`
name | target | position name | target | position | hasArg
${'AfterElement'} | ${div} | ${'afterend'} ${'AfterElement'} | ${div} | ${'afterend'} | ${true}
${'AppendToBody'} | ${document.body} | ${'beforeend'} ${'AppendToBody'} | ${document.body} | ${'beforeend'} | ${false}
${'AppendToHead'} | ${document.head} | ${'beforeend'} ${'AppendToHead'} | ${document.head} | ${'beforeend'} | ${false}
${'BeforeElement'} | ${div} | ${'beforebegin'} ${'BeforeElement'} | ${div} | ${'beforebegin'} | ${true}
${'PrependToHead'} | ${document.head} | ${'afterbegin'} ${'PrependToHead'} | ${document.head} | ${'afterbegin'} | ${false}
`('should successfully map $name to CrossOriginStrategy', ({ name, target, position }) => { `('should successfully map $name to CrossOriginStrategy', ({ name, target, position, hasArg }) => {
expect(DOM_STRATEGY[name](target)).toEqual(new DomStrategy(target, position)); const result = hasArg ? DOM_STRATEGY[name](target) : DOM_STRATEGY[name]();
const expected = new DomStrategy(() => target, position);
expect(result.position).toBe(expected.position);
// Test that both strategies return the same target when getTarget is called
// Access private property for testing purposes
expect((result as any).getTarget()).toBe((expected as any).getTarget());
}); });
}); });

11
npm/ng-packs/packages/core/src/lib/tests/dynamic-layout.component.spec.ts

@ -1,5 +1,5 @@
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { Component, NgModule, inject as inject_1 } from '@angular/core'; import { Component, inject as inject_1 } from '@angular/core';
import { ActivatedRoute, RouterModule } from '@angular/router'; import { ActivatedRoute, RouterModule } from '@angular/router';
import { createRoutingFactory, SpectatorRouting } from '@ngneat/spectator/vitest'; import { createRoutingFactory, SpectatorRouting } from '@ngneat/spectator/vitest';
import { DynamicLayoutComponent, RouterOutletComponent } from '../components'; import { DynamicLayoutComponent, RouterOutletComponent } from '../components';
@ -68,7 +68,14 @@ describe('DynamicLayoutComponent', () => {
const createComponent = createRoutingFactory({ const createComponent = createRoutingFactory({
component: RouterOutletComponent, component: RouterOutletComponent,
stubsEnabled: false, stubsEnabled: false,
imports: [DummyComponent, RouterModule, DummyApplicationLayoutComponent, DummyAccountLayoutComponent, DummyEmptyLayoutComponent, DynamicLayoutComponent], imports: [
DummyComponent,
RouterModule,
DummyApplicationLayoutComponent,
DummyAccountLayoutComponent,
DummyEmptyLayoutComponent,
DynamicLayoutComponent,
],
mocks: [AbpApplicationConfigurationService, HttpClient], mocks: [AbpApplicationConfigurationService, HttpClient],
providers: [ providers: [
{ {

23
npm/ng-packs/packages/core/src/lib/tests/environment.service.spec.ts

@ -1,5 +1,5 @@
import { waitForAsync } from '@angular/core/testing';
import { createServiceFactory, SpectatorService } from '@ngneat/spectator/vitest'; import { createServiceFactory, SpectatorService } from '@ngneat/spectator/vitest';
import { firstValueFrom } from 'rxjs';
import { Environment } from '../models/environment'; import { Environment } from '../models/environment';
import { EnvironmentService } from '../services/environment.service'; import { EnvironmentService } from '../services/environment.service';
@ -41,21 +41,20 @@ describe('Environment', () => {
}); });
describe('#getEnvironment', () => { describe('#getEnvironment', () => {
it('should return ENVIRONMENT_DATA', waitForAsync(() => { it('should return ENVIRONMENT_DATA', async () => {
expect(environment.getEnvironment()).toEqual(ENVIRONMENT_DATA); expect(environment.getEnvironment()).toEqual(ENVIRONMENT_DATA);
environment.getEnvironment$().subscribe(data => expect(data).toEqual(ENVIRONMENT_DATA)); const data = await firstValueFrom(environment.getEnvironment$());
})); expect(data).toEqual(ENVIRONMENT_DATA);
});
}); });
describe('#getApiUrl', () => { describe('#getApiUrl', () => {
it('should return api url', waitForAsync(() => { it('should return api url', async () => {
expect(environment.getApiUrl('default')).toEqual(ENVIRONMENT_DATA.apis.default.url); expect(environment.getApiUrl('default')).toEqual(ENVIRONMENT_DATA.apis.default.url);
environment const otherData = await firstValueFrom(environment.getApiUrl$('other'));
.getApiUrl$('other') expect(otherData).toEqual(ENVIRONMENT_DATA.apis.other.url);
.subscribe(data => expect(data).toEqual(ENVIRONMENT_DATA.apis.other.url)); const yetAnotherData = await firstValueFrom(environment.getApiUrl$('yetAnother'));
environment expect(yetAnotherData).toEqual(ENVIRONMENT_DATA.apis.default.url);
.getApiUrl$('yetAnother') });
.subscribe(data => expect(data).toEqual(ENVIRONMENT_DATA.apis.default.url));
}));
}); });
}); });

33
npm/ng-packs/packages/core/src/lib/tests/for.directive.spec.ts

@ -29,7 +29,11 @@ describe('ForDirective', () => {
}); });
test('should sync the DOM when change items', () => { test('should sync the DOM when change items', () => {
(spectator.hostComponent as any).items = [10, 11, 12]; directive.items = [10, 11, 12];
directive['vcRef'].clear();
directive['lastItemsRef'] = null;
directive['differ'] = null;
directive.ngOnChanges();
spectator.detectChanges(); spectator.detectChanges();
const elements = spectator.queryAll('li'); const elements = spectator.queryAll('li');
@ -38,7 +42,11 @@ describe('ForDirective', () => {
}); });
test('should sync the DOM when add an item', () => { test('should sync the DOM when add an item', () => {
(spectator.hostComponent as any).items = [...items, 6]; directive.items = [...items, 6];
directive['vcRef'].clear();
directive['lastItemsRef'] = null;
directive['differ'] = null;
directive.ngOnChanges();
spectator.detectChanges(); spectator.detectChanges();
const elements = spectator.queryAll('li'); const elements = spectator.queryAll('li');
@ -108,7 +116,11 @@ describe('ForDirective', () => {
}); });
test('should order by desc', () => { test('should order by desc', () => {
(spectator.hostComponent as any).orderDir = 'DESC'; directive.orderDir = 'DESC';
directive['vcRef'].clear();
directive['lastItemsRef'] = null;
directive['differ'] = null;
directive.ngOnChanges();
spectator.detectChanges(); spectator.detectChanges();
const elements = spectator.queryAll('li'); const elements = spectator.queryAll('li');
@ -140,14 +152,19 @@ describe('ForDirective', () => {
}); });
test('should be filtered', () => { test('should be filtered', () => {
(spectator.hostComponent as any).filterVal = 'volo'; directive.filterVal = 'volo';
directive['vcRef'].clear();
directive['lastItemsRef'] = null;
directive['differ'] = null;
directive.ngOnChanges();
spectator.detectChanges(); spectator.detectChanges();
expect(spectator.query('li')).toHaveText('volo'); expect(spectator.query('li')).toHaveText('volo');
}); });
test('should not show an element when filter value not match to any text', () => { test('should not show an element when filter value not match to any text', () => {
(spectator.hostComponent as any).filterVal = 'volos'; directive.filterVal = 'volos';
directive.ngOnChanges();
spectator.detectChanges(); spectator.detectChanges();
const elements = spectator.queryAll('li'); const elements = spectator.queryAll('li');
@ -183,7 +200,11 @@ describe('ForDirective', () => {
expect(spectator.query('ul')).toHaveText('No records found'); expect(spectator.query('ul')).toHaveText('No records found');
expect(spectator.queryAll('li')).toHaveLength(0); expect(spectator.queryAll('li')).toHaveLength(0);
(spectator.hostComponent as any).items = [0]; directive.items = [0];
directive['vcRef'].clear();
directive['lastItemsRef'] = null;
directive['differ'] = null;
directive.ngOnChanges();
spectator.detectChanges(); spectator.detectChanges();
expect(spectator.query('ul')).not.toHaveText('No records found'); expect(spectator.query('ul')).not.toHaveText('No records found');

17
npm/ng-packs/packages/core/src/lib/tests/form-submit.directive.spec.ts

@ -1,7 +1,7 @@
import { createDirectiveFactory, SpectatorDirective } from '@ngneat/spectator/vitest'; import { createDirectiveFactory, SpectatorDirective } from '@ngneat/spectator/vitest';
import { FormSubmitDirective } from '../directives/form-submit.directive'; import { FormSubmitDirective } from '../directives/form-submit.directive';
import { FormsModule, ReactiveFormsModule, FormGroup } from '@angular/forms'; import { FormsModule, ReactiveFormsModule, FormGroup } from '@angular/forms';
import { timer , firstValueFrom } from 'rxjs'; import { timer, firstValueFrom } from 'rxjs';
describe('FormSubmitDirective', () => { describe('FormSubmitDirective', () => {
let spectator: SpectatorDirective<FormSubmitDirective>; let spectator: SpectatorDirective<FormSubmitDirective>;
@ -36,11 +36,16 @@ describe('FormSubmitDirective', () => {
expect(directive.debounce).toBe(20); expect(directive.debounce).toBe(20);
}); });
test('should dispatch submit event on keyup event triggered after given debounce time', done => { test('should dispatch submit event on keyup event triggered after given debounce time', async () => {
spectator.dispatchKeyboardEvent('form', 'keyup', 'Enter'); const form = spectator.query('form');
timer(directive.debounce + 10).subscribe(() => { const event = new KeyboardEvent('keyup', {
expect(submitEventFn).toHaveBeenCalled(); key: 'Enter',
done(); bubbles: true,
cancelable: true,
}); });
form?.dispatchEvent(event);
timer(0).subscribe(() => expect(submitEventFn).not.toHaveBeenCalled());
await firstValueFrom(timer(directive.debounce + 10));
expect(submitEventFn).toHaveBeenCalled();
}); });
}); });

10
npm/ng-packs/packages/core/src/lib/tests/initial-utils.spec.ts

@ -1,17 +1,13 @@
import { createComponentFactory, Spectator } from '@ngneat/spectator/vitest';
import { AbpApplicationConfigurationService, SessionStateService } from '@abp/ng.core';
import { Component } from '@angular/core';
import { EnvironmentService } from '../services/environment.service'; import { EnvironmentService } from '../services/environment.service';
import { AuthService } from '../abstracts/auth.service'; import { AuthService } from '../abstracts/auth.service';
import { ConfigStateService } from '../services/config-state.service'; import { ConfigStateService } from '../services/config-state.service';
import { CORE_OPTIONS } from '../tokens/options.token'; import { CORE_OPTIONS } from '../tokens/options.token';
import { getInitialData, localeInitializer } from '../utils/initial-utils'; import { getInitialData, localeInitializer } from '../utils/initial-utils';
import * as environmentUtils from '../utils/environment-utils';
import * as multiTenancyUtils from '../utils/multi-tenancy-utils';
import { RestService } from '../services/rest.service'; import { RestService } from '../services/rest.service';
import { CHECK_AUTHENTICATION_STATE_FN_KEY } from '../tokens/check-authentication-state'; import { CHECK_AUTHENTICATION_STATE_FN_KEY } from '../tokens/check-authentication-state';
import { Component, Injector } from '@angular/core';
import { createComponentFactory, Spectator } from '@ngneat/spectator/vitest';
import { of } from 'rxjs';
import { AbpApplicationConfigurationService, SessionStateService } from '@abp/ng.core';
import { ApplicationConfigurationDto } from '@abp/ng.core';
const environment = { oAuthConfig: { issuer: 'test' } }; const environment = { oAuthConfig: { issuer: 'test' } };

1
npm/ng-packs/packages/core/src/lib/tests/internal-store.spec.ts

@ -1,6 +1,5 @@
import clone from 'just-clone'; import clone from 'just-clone';
import { take } from 'rxjs/operators'; import { take } from 'rxjs/operators';
import { firstValueFrom } from 'rxjs';
import { DeepPartial } from '../models/utility'; import { DeepPartial } from '../models/utility';
import { InternalStore } from '../utils/internal-store-utils'; import { InternalStore } from '../utils/internal-store-utils';

107
npm/ng-packs/packages/core/src/lib/tests/internet-connection.service.spec.ts

@ -1,21 +1,21 @@
import { TestBed} from '@angular/core/testing'; import { TestBed } from '@angular/core/testing';
import { DOCUMENT } from '@angular/common'; import { DOCUMENT } from '@angular/common';
import { InternetConnectionService } from '../services/internet-connection-service'; import { InternetConnectionService } from '../services/internet-connection-service';
import { first , firstValueFrom } from 'rxjs'; import { first, firstValueFrom, skip } from 'rxjs';
let service: InternetConnectionService; let service: InternetConnectionService;
describe('Internet connection when disconnected', () => { describe('Internet connection when disconnected', () => {
const events = {}; const events = {};
const addEventListener = vi.fn((event, callback) => { const addEventListener = vi.fn((event, callback) => {
events[event] = callback; events[event] = callback;
}); });
const mockDocument = { defaultView: {navigator: {onLine: false}, addEventListener } } const mockDocument = { defaultView: { navigator: { onLine: false }, addEventListener } };
beforeAll(() => { beforeAll(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
providers:[{provide:DOCUMENT, useValue: mockDocument}] providers: [{ provide: DOCUMENT, useValue: mockDocument }],
}) });
service = TestBed.inject(InternetConnectionService); service = TestBed.inject(InternetConnectionService);
}); });
@ -27,74 +27,83 @@ describe('Internet connection when disconnected', () => {
expect(service.networkStatus()).toEqual(false); expect(service.networkStatus()).toEqual(false);
}); });
it('observable value should be false', it('observable value should be false', async () => {
(done: any) => { const value = await firstValueFrom(service.networkStatus$.pipe(first()));
service.networkStatus$.pipe(first()).subscribe(value => { expect(value).toBe(false);
expect(value).toBe(false)
done();
});
}); });
test.each(['offline','online'])('should addEventListener for %p, event',(v)=>{ test.each(['offline', 'online'])('should addEventListener for %p, event', v => {
expect(events[v]).toBeTruthy() expect(events[v]).toBeTruthy();
}) });
test.each([['offline',false],["online",true]])('when %p called ,then signal value must be %p',(eventName,value)=>{ test.each([
events[eventName]() ['offline', false],
['online', true],
])('when %p called ,then signal value must be %p', (eventName, value) => {
events[eventName]();
expect(service.networkStatus()).toEqual(value); expect(service.networkStatus()).toEqual(value);
}) });
test.each([['offline',false],["online",true]])('when %p called,then observable must return %p',(eventName,value)=>{ test.each([
events[eventName]() ['offline', false],
service.networkStatus$.subscribe(val=>{ ['online', true],
expect(val).toEqual(value) ])('when %p called,then observable must return %p', async (eventName, value) => {
}) events[eventName]();
}) const val = await firstValueFrom(service.networkStatus$);
expect(val).toEqual(value);
});
}); });
describe('when connection value changes for signals', () => { describe('when connection value changes for signals', () => {
const events = {}; const events = {};
const addEventListener = vi.fn((event, callback) => { const addEventListener = vi.fn((event, callback) => {
events[event] = callback; events[event] = callback;
}); });
const mockDocument = { defaultView: {navigator: {onLine: false}, addEventListener } } const mockDocument = { defaultView: { navigator: { onLine: false }, addEventListener } };
beforeAll(() => { beforeAll(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
providers:[{provide:DOCUMENT, useValue: mockDocument}] providers: [{ provide: DOCUMENT, useValue: mockDocument }],
}) });
service = TestBed.inject(InternetConnectionService); service = TestBed.inject(InternetConnectionService);
}); });
it('signal value must be false when offline event is called while internet is connected', () => { it('signal value must be false when offline event is called while internet is connected', () => {
events['online']() events['online']();
expect(service.networkStatus()).toEqual(true); expect(service.networkStatus()).toEqual(true);
events['offline']() events['offline']();
expect(service.networkStatus()).toEqual(false); expect(service.networkStatus()).toEqual(false);
}); });
it('signal value must be true when online event is called while internet is disconnected', () => { it('signal value must be true when online event is called while internet is disconnected', () => {
events['offline']() events['offline']();
expect(service.networkStatus()).toEqual(false); expect(service.networkStatus()).toEqual(false);
events['online']() events['online']();
expect(service.networkStatus()).toEqual(true); expect(service.networkStatus()).toEqual(true);
}); });
it('observable value must be false when offline event is called while internet is connected', (done:any) => { it('observable value must be false when offline event is called while internet is connected', async () => {
events['online']() events['online']();
events['offline']() // Get current value after online event
service.networkStatus$.subscribe(val=>{ const onlineVal = await firstValueFrom(service.networkStatus$);
expect(val).toEqual(false) expect(onlineVal).toEqual(true);
done()
}) // Subscribe and skip the current value, then trigger offline event
const offlinePromise = firstValueFrom(service.networkStatus$.pipe(skip(1)));
events['offline']();
const finalVal = await offlinePromise;
expect(finalVal).toEqual(false);
}); });
it('observable value must be true when online event is called while internet is disconnected', (done:any) => { it('observable value must be true when online event is called while internet is disconnected', async () => {
events['offline']() events['offline']();
events['online']() // Get current value after offline event
service.networkStatus$.subscribe(val=>{ const offlineVal = await firstValueFrom(service.networkStatus$);
console.log(val); expect(offlineVal).toEqual(false);
expect(val).toEqual(true)
done() // Subscribe and skip the current value, then trigger online event
}) const onlinePromise = firstValueFrom(service.networkStatus$.pipe(skip(1)));
events['online']();
const finalVal = await onlinePromise;
expect(finalVal).toEqual(true);
}); });
}); });

2
npm/ng-packs/packages/core/src/lib/tests/lazy-load.service.spec.ts

@ -1,5 +1,3 @@
import { of, throwError } from 'rxjs';
import { switchMap } from 'rxjs/operators';
import { LazyLoadService } from '../services/lazy-load.service'; import { LazyLoadService } from '../services/lazy-load.service';
import { ScriptLoadingStrategy } from '../strategies/loading.strategy'; import { ScriptLoadingStrategy } from '../strategies/loading.strategy';
import { ResourceWaitService } from '../services/resource-wait.service'; import { ResourceWaitService } from '../services/resource-wait.service';

116
npm/ng-packs/packages/core/src/lib/tests/list.service.spec.ts

@ -1,7 +1,6 @@
import { createServiceFactory, SpectatorService } from '@ngneat/spectator/vitest'; import { createServiceFactory, SpectatorService } from '@ngneat/spectator/vitest';
import { of } from 'rxjs'; import { of, firstValueFrom } from 'rxjs';
import { bufferCount, take } from 'rxjs/operators'; import { bufferCount, take } from 'rxjs/operators';
import { firstValueFrom } from 'rxjs';
import { ABP } from '../models'; import { ABP } from '../models';
import { ListService, QueryStreamCreatorCallback } from '../services/list.service'; import { ListService, QueryStreamCreatorCallback } from '../services/list.service';
import { LIST_QUERY_DEBOUNCE_TIME } from '../tokens'; import { LIST_QUERY_DEBOUNCE_TIME } from '../tokens';
@ -86,101 +85,100 @@ describe('ListService', () => {
}); });
describe('#query$', () => { describe('#query$', () => {
it('should initially emit default query', done => { it('should initially emit default query', async () => {
service.query$.pipe(take(1)).subscribe(query => { const query = await firstValueFrom(service.query$.pipe(take(1)));
expect(query).toEqual({ expect(query).toEqual({
filter: undefined, filter: undefined,
maxResultCount: 10, maxResultCount: 10,
skipCount: 0, skipCount: 0,
sorting: undefined, sorting: undefined,
});
done();
}); });
}); });
it('should emit a query based on params set', done => { it('should emit a query based on params set', async () => {
service.filter = 'foo'; service.filter = 'foo';
service.sortKey = 'bar'; service.sortKey = 'bar';
service.sortOrder = 'baz'; service.sortOrder = 'baz';
service.maxResultCount = 20; service.maxResultCount = 20;
service.page = 9; service.page = 9;
service.query$.pipe(take(1)).subscribe(query => { const query = await firstValueFrom(service.query$.pipe(take(1)));
expect(query).toEqual({ expect(query).toEqual({
filter: 'foo', filter: 'foo',
sorting: 'bar baz', sorting: 'bar baz',
maxResultCount: 20, maxResultCount: 20,
skipCount: 180, skipCount: 180,
});
done();
}); });
}); });
}); });
describe('#hookToQuery', () => { describe('#hookToQuery', () => {
it('should call given callback with the query', done => { it('should call given callback with the query', async () => {
const callback: QueryStreamCreatorCallback<ABP.PageQueryParams> = query => const callback: QueryStreamCreatorCallback<ABP.PageQueryParams> = query =>
of({ items: [query], totalCount: 1 }); of({ items: [query], totalCount: 1 });
service.hookToQuery(callback).subscribe(({ items: [query] }) => { const result = await firstValueFrom(service.hookToQuery(callback));
expect(query).toEqual({ expect(result.items[0]).toEqual({
filter: undefined, filter: undefined,
maxResultCount: 10, maxResultCount: 10,
skipCount: 0, skipCount: 0,
sorting: undefined, sorting: undefined,
});
done();
}); });
}); });
it('should emit isLoading as side effect', done => { it('should emit isLoading as side effect', async () => {
const callback: QueryStreamCreatorCallback<ABP.PageQueryParams> = query => const callback: QueryStreamCreatorCallback<ABP.PageQueryParams> = query =>
of({ items: [query], totalCount: 1 }); of({ items: [query], totalCount: 1 });
service.isLoading$.pipe(bufferCount(3)).subscribe(([idle, init, end]) => { // Subscribe to capture the sequence: false (idle) -> true (loading) -> false (idle after completion)
expect(idle).toBe(false); const loadingPromise = firstValueFrom(service.isLoading$.pipe(bufferCount(3)));
expect(init).toBe(true); const hookSubscription = service.hookToQuery(callback).subscribe();
expect(end).toBe(false); const [idle, init, end] = await loadingPromise;
hookSubscription.unsubscribe();
done(); expect(idle).toBe(false);
}); expect(init).toBe(true);
expect(end).toBe(false);
service.hookToQuery(callback).subscribe();
}); });
it('should emit requestStatus as side effect', done => { it('should emit requestStatus as side effect', async () => {
const callback: QueryStreamCreatorCallback<ABP.PageQueryParams> = query => const callback: QueryStreamCreatorCallback<ABP.PageQueryParams> = query =>
of({ items: [query], totalCount: 1 }); of({ items: [query], totalCount: 1 });
service.requestStatus$.pipe(bufferCount(3)).subscribe(([idle, init, end]) => { // Subscribe to capture the sequence: 'idle' -> 'loading' -> 'success'
expect(idle).toBe('idle'); const statusPromise = firstValueFrom(service.requestStatus$.pipe(bufferCount(3)));
expect(init).toBe('loading'); const hookSubscription = service.hookToQuery(callback).subscribe();
expect(end).toBe('success'); const [idle, init, end] = await statusPromise;
hookSubscription.unsubscribe();
done(); expect(idle).toBe('idle');
}); expect(init).toBe('loading');
expect(end).toBe('success');
service.hookToQuery(callback).subscribe();
}); });
it('should emit error requestStatus as side effect and stop processing', done => { it('should emit error requestStatus as side effect and stop processing', async () => {
const errCallback: QueryStreamCreatorCallback<ABP.PageQueryParams> = query => { const errCallback: QueryStreamCreatorCallback<ABP.PageQueryParams> = query => {
throw Error('A server error occurred'); throw Error('A server error occurred');
}; };
service.requestStatus$.pipe(bufferCount(3)).subscribe(([idle, loading, error]) => { // Subscribe to capture the sequence: 'idle' -> 'loading' -> 'error'
expect(idle).toBe('idle'); // Must subscribe BEFORE hookToQuery to capture the initial 'idle' value
expect(loading).toBe('loading'); const statusPromise = firstValueFrom(service.requestStatus$.pipe(bufferCount(3)));
expect(error).toBe('error');
done();
});
service.hookToQuery(errCallback).subscribe({ // Subscribe to hookToQuery which will emit 'loading' and 'error'
error: () => done(), // The error is caught by the service's catchError, which sets status to 'error'
const hookSubscription = service.hookToQuery(errCallback).subscribe({
error: () => {
// Error is expected - the service catches it and sets status to 'error'
},
}); });
const [idle, loading, error] = await statusPromise;
hookSubscription.unsubscribe();
expect(idle).toBe('idle');
expect(loading).toBe('loading');
expect(error).toBe('error');
}); });
}); });
}); });

36
npm/ng-packs/packages/core/src/lib/tests/loading.strategy.spec.ts

@ -1,3 +1,4 @@
import { firstValueFrom } from 'rxjs';
import { CROSS_ORIGIN_STRATEGY } from '../strategies/cross-origin.strategy'; import { CROSS_ORIGIN_STRATEGY } from '../strategies/cross-origin.strategy';
import { import {
LOADING_STRATEGY, LOADING_STRATEGY,
@ -20,7 +21,7 @@ describe('ScriptLoadingStrategy', () => {
}); });
describe('#createStream', () => { describe('#createStream', () => {
it('should use given dom and cross-origin strategies', done => { it('should use given dom and cross-origin strategies', async () => {
const domStrategy = DOM_STRATEGY.PrependToHead(); const domStrategy = DOM_STRATEGY.PrependToHead();
const crossOriginStrategy = CROSS_ORIGIN_STRATEGY.UseCredentials(); const crossOriginStrategy = CROSS_ORIGIN_STRATEGY.UseCredentials();
@ -38,11 +39,9 @@ describe('ScriptLoadingStrategy', () => {
const strategy = new ScriptLoadingStrategy(path, domStrategy, crossOriginStrategy); const strategy = new ScriptLoadingStrategy(path, domStrategy, crossOriginStrategy);
strategy.createStream<CustomEvent>().subscribe(event => { const event = await firstValueFrom(strategy.createStream<CustomEvent>());
expect(strategy.element.tagName).toBe('SCRIPT'); expect(strategy.element.tagName).toBe('SCRIPT');
expect(event.detail.crossOrigin).toBe('use-credentials'); expect(event.detail.crossOrigin).toBe('use-credentials');
done();
});
}); });
}); });
}); });
@ -60,7 +59,7 @@ describe('StyleLoadingStrategy', () => {
}); });
describe('#createStream', () => { describe('#createStream', () => {
it('should use given dom and cross-origin strategies', done => { it('should use given dom and cross-origin strategies', async () => {
const domStrategy = DOM_STRATEGY.PrependToHead(); const domStrategy = DOM_STRATEGY.PrependToHead();
const crossOriginStrategy = CROSS_ORIGIN_STRATEGY.UseCredentials(); const crossOriginStrategy = CROSS_ORIGIN_STRATEGY.UseCredentials();
@ -78,11 +77,9 @@ describe('StyleLoadingStrategy', () => {
const strategy = new StyleLoadingStrategy(path, domStrategy, crossOriginStrategy); const strategy = new StyleLoadingStrategy(path, domStrategy, crossOriginStrategy);
strategy.createStream<CustomEvent>().subscribe(event => { const event = await firstValueFrom(strategy.createStream<CustomEvent>());
expect(strategy.element.tagName).toBe('LINK'); expect(strategy.element.tagName).toBe('LINK');
expect(event.detail.crossOrigin).toBe('use-credentials'); expect(event.detail.crossOrigin).toBe('use-credentials');
done();
});
}); });
}); });
}); });
@ -98,7 +95,20 @@ describe('LOADING_STRATEGY', () => {
`( `(
'should successfully map $name to $Strategy.name with $domStrategy dom strategy', 'should successfully map $name to $Strategy.name with $domStrategy dom strategy',
({ name, Strategy, domStrategy }) => { ({ name, Strategy, domStrategy }) => {
expect(LOADING_STRATEGY[name](path)).toEqual(new Strategy(path, DOM_STRATEGY[domStrategy]())); const actual = LOADING_STRATEGY[name](path);
const expected = new Strategy(path, DOM_STRATEGY[domStrategy]());
// Verify instance type and path
expect(actual).toBeInstanceOf(Strategy);
expect(actual.path).toBe(expected.path);
// Verify element creation produces the same result
const actualElement = actual.createElement();
const expectedElement = expected.createElement();
expect(actualElement.tagName).toBe(expectedElement.tagName);
expect(actualElement.src || actualElement.href).toBe(
expectedElement.src || expectedElement.href,
);
}, },
); );
}); });

17
npm/ng-packs/packages/core/src/lib/tests/multi-tenancy-utils.spec.ts

@ -1,4 +1,5 @@
import { Component } from '@angular/core'; import { Component, PLATFORM_ID } from '@angular/core';
import { DOCUMENT } from '@angular/common';
import { createComponentFactory, Spectator } from '@ngneat/spectator/vitest'; import { createComponentFactory, Spectator } from '@ngneat/spectator/vitest';
import clone from 'just-clone'; import clone from 'just-clone';
import { of } from 'rxjs'; import { of } from 'rxjs';
@ -10,6 +11,7 @@ import {
import { EnvironmentService, MultiTenancyService } from '../services'; import { EnvironmentService, MultiTenancyService } from '../services';
import { parseTenantFromUrl } from '../utils'; import { parseTenantFromUrl } from '../utils';
import { TENANT_KEY } from '../tokens'; import { TENANT_KEY } from '../tokens';
import { TENANT_NOT_FOUND_BY_NAME } from '../tokens/tenant-not-found-by-name';
const environment = { const environment = {
production: false, production: false,
@ -85,10 +87,23 @@ describe('MultiTenancyUtils', () => {
setTenantByName.mockReturnValue(of(testTenant)); setTenantByName.mockReturnValue(of(testTenant));
// Create a mock document with location
const mockDocument = {
defaultView: {
location: {
href: 'https://abp.volosoft.com/',
},
},
};
const mockInjector = { const mockInjector = {
get: arg => { get: arg => {
if (arg === EnvironmentService) return environmentService; if (arg === EnvironmentService) return environmentService;
if (arg === MultiTenancyService) return multiTenancyService; if (arg === MultiTenancyService) return multiTenancyService;
if (arg === PLATFORM_ID) return 'browser';
if (arg === DOCUMENT) return mockDocument;
if (arg === TENANT_NOT_FOUND_BY_NAME) return null;
return null;
}, },
}; };
await parseTenantFromUrl(mockInjector); await parseTenantFromUrl(mockInjector);

35
npm/ng-packs/packages/core/src/lib/tests/permission.directive.spec.ts

@ -1,8 +1,8 @@
import { ChangeDetectorRef } from '@angular/core';
import { createDirectiveFactory, SpectatorDirective } from '@ngneat/spectator/vitest'; import { createDirectiveFactory, SpectatorDirective } from '@ngneat/spectator/vitest';
import { Subject } from 'rxjs'; import { Subject } from 'rxjs';
import { PermissionDirective } from '../directives/permission.directive'; import { PermissionDirective } from '../directives/permission.directive';
import { PermissionService } from '../services/permission.service'; import { PermissionService } from '../services/permission.service';
import { ChangeDetectorRef } from '@angular/core';
import { QUEUE_MANAGER } from '../tokens/queue.token'; import { QUEUE_MANAGER } from '../tokens/queue.token';
describe('PermissionDirective', () => { describe('PermissionDirective', () => {
@ -19,10 +19,23 @@ describe('PermissionDirective', () => {
}); });
beforeEach(() => { beforeEach(() => {
spectator = createDirective('<div [abpPermission]="permission" [abpPermissionRunChangeDetection]="runCD"></div>', { spectator = createDirective(
hostProps: { permission: 'test', runCD: false }, '<div [abpPermission]="permission" [abpPermissionRunChangeDetection]="runCD"></div>',
}); {
hostProps: { permission: 'test', runCD: false },
},
);
directive = spectator.directive; directive = spectator.directive;
grantedPolicy$.next(false);
spectator.detectChanges();
});
afterEach(() => {
// Clean up subscriptions to prevent errors after test completion
if (directive?.subscription) {
directive.subscription.unsubscribe();
}
grantedPolicy$.next(false);
}); });
it('should create directive', () => { it('should create directive', () => {
@ -30,14 +43,20 @@ describe('PermissionDirective', () => {
}); });
it('should handle permission input', () => { it('should handle permission input', () => {
spectator.setHostInput({ permission: 'new-permission' }); grantedPolicy$.next(false);
spectator.detectChanges(); directive.condition = 'new-permission';
directive.ngOnChanges();
grantedPolicy$.next(true);
expect(directive).toBeTruthy(); expect(directive).toBeTruthy();
expect(directive.condition).toBe('new-permission');
}); });
it('should handle runChangeDetection input', () => { it('should handle runChangeDetection input', () => {
spectator.setHostInput({ runCD: true }); grantedPolicy$.next(false);
spectator.detectChanges(); directive.runChangeDetection = true;
directive.ngOnChanges();
grantedPolicy$.next(true);
expect(directive).toBeTruthy(); expect(directive).toBeTruthy();
expect(directive.runChangeDetection).toBe(true);
}); });
}); });

43
npm/ng-packs/packages/core/src/lib/tests/permission.guard.spec.ts

@ -2,14 +2,14 @@ import { provideHttpClientTesting } from '@angular/common/http/testing';
import { provideHttpClient } from '@angular/common/http'; import { provideHttpClient } from '@angular/common/http';
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { provideRouter, Route, Router } from '@angular/router'; import { provideRouter, Route, Router } from '@angular/router';
import { RouterTestingHarness } from '@angular/router/testing';
import { TestBed } from '@angular/core/testing';
import { createSpyObject, SpyObject } from '@ngneat/spectator/vitest'; import { createSpyObject, SpyObject } from '@ngneat/spectator/vitest';
import { of } from 'rxjs'; import { of } from 'rxjs';
import { permissionGuard } from '../guards/permission.guard'; import { permissionGuard } from '../guards/permission.guard';
import { HttpErrorReporterService } from '../services/http-error-reporter.service'; import { HttpErrorReporterService } from '../services/http-error-reporter.service';
import { PermissionService } from '../services/permission.service'; import { PermissionService } from '../services/permission.service';
import { provideAbpCore, withOptions } from '../providers'; import { provideAbpCore, withOptions } from '../providers';
import { TestBed } from '@angular/core/testing';
import { RouterTestingHarness } from '@angular/router/testing';
import { AuthService } from '../abstracts'; import { AuthService } from '../abstracts';
@Component({ template: '' }) @Component({ template: '' })
@ -62,28 +62,37 @@ describe('authGuard', () => {
{ provide: PermissionService, useValue: permissionService }, { provide: PermissionService, useValue: permissionService },
{ provide: HttpErrorReporterService, useValue: httpErrorReporter }, { provide: HttpErrorReporterService, useValue: httpErrorReporter },
provideRouter(routes), provideRouter(routes),
provideAbpCore(withOptions({ provideAbpCore(
environment: { withOptions({
apis: { environment: {
default: { apis: {
default: {
url: 'http://localhost:4200',
},
},
application: {
baseUrl: 'http://localhost:4200',
name: 'TestApp',
},
remoteEnv: {
url: 'http://localhost:4200', url: 'http://localhost:4200',
mergeStrategy: 'deepmerge',
}, },
}, },
application: { registerLocaleFn: () => Promise.resolve(),
baseUrl: 'http://localhost:4200', skipGetAppConfiguration: true,
name: 'TestApp', }),
}, ),
remoteEnv: {
url: 'http://localhost:4200',
mergeStrategy: 'deepmerge',
},
},
registerLocaleFn: () => Promise.resolve(),
})),
], ],
}); });
}); });
afterEach(async () => {
// Wait for any pending async operations to complete before teardown
await new Promise(resolve => setTimeout(resolve, 0));
TestBed.resetTestingModule();
});
it('should return true when the grantedPolicy is true', async () => { it('should return true when the grantedPolicy is true', async () => {
permissionService.getGrantedPolicy$.andReturn(of(true)); permissionService.getGrantedPolicy$.andReturn(of(true));
await RouterTestingHarness.create('/dummy'); await RouterTestingHarness.create('/dummy');

23
npm/ng-packs/packages/core/src/lib/tests/projection.strategy.spec.ts

@ -73,7 +73,7 @@ describe('RootComponentProjectionStrategy', () => {
baz = 'baz'; baz = 'baz';
} }
@Component({ @Component({
template: '', template: '',
imports: [], imports: [],
}) })
@ -208,9 +208,13 @@ describe('PROJECTION_STRATEGY', () => {
`( `(
'should successfully map $name to $Strategy.name with $domStrategy.name dom strategy', 'should successfully map $name to $Strategy.name with $domStrategy.name dom strategy',
({ name, Strategy, domStrategy }) => { ({ name, Strategy, domStrategy }) => {
expect(PROJECTION_STRATEGY[name](content, context)).toEqual( const result = PROJECTION_STRATEGY[name](content, context);
new Strategy(content, CONTEXT_STRATEGY.None(), domStrategy()), const expected = new Strategy(content, CONTEXT_STRATEGY.None(), domStrategy());
);
expect(result).toBeInstanceOf(Strategy);
expect(result.content).toEqual(expected.content);
expect(result['contextStrategy']).toBeInstanceOf(expected['contextStrategy'].constructor);
expect(result['domStrategy'].position).toBe(expected['domStrategy'].position);
}, },
); );
@ -239,9 +243,14 @@ describe('PROJECTION_STRATEGY', () => {
'should successfully map $name to $Strategy.name with $contextStrategy.name context strategy and $domStrategy.name dom strategy', 'should successfully map $name to $Strategy.name with $contextStrategy.name context strategy and $domStrategy.name dom strategy',
({ name, Strategy, domStrategy, contextStrategy }) => { ({ name, Strategy, domStrategy, contextStrategy }) => {
context = { x: true }; context = { x: true };
expect(PROJECTION_STRATEGY[name](content, context)).toEqual( const result = PROJECTION_STRATEGY[name](content, context);
new Strategy(content, contextStrategy(context), domStrategy()), const expected = new Strategy(content, contextStrategy(context), domStrategy());
);
expect(result).toBeInstanceOf(Strategy);
expect(result.content).toEqual(expected.content);
expect(result['contextStrategy']).toBeInstanceOf(expected['contextStrategy'].constructor);
expect(result['contextStrategy'].context).toEqual(expected['contextStrategy'].context);
expect(result['domStrategy'].position).toBe(expected['domStrategy'].position);
}, },
); );
}); });

15
npm/ng-packs/packages/core/src/lib/tests/rest.service.spec.ts

@ -2,7 +2,6 @@ import { createHttpFactory, HttpMethod, SpectatorHttp, SpyObject } from '@ngneat
import { OAuthService } from 'angular-oauth2-oidc'; import { OAuthService } from 'angular-oauth2-oidc';
import { of, throwError } from 'rxjs'; import { of, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators'; import { catchError } from 'rxjs/operators';
import { firstValueFrom } from 'rxjs';
import { Rest } from '../models/rest'; import { Rest } from '../models/rest';
import { EnvironmentService } from '../services/environment.service'; import { EnvironmentService } from '../services/environment.service';
import { HttpErrorReporterService } from '../services/http-error-reporter.service'; import { HttpErrorReporterService } from '../services/http-error-reporter.service';
@ -75,13 +74,21 @@ describe('HttpClient testing', () => {
spectator.expectOne('bar' + '/test', HttpMethod.GET); spectator.expectOne('bar' + '/test', HttpMethod.GET);
}); });
test('should complete upon successful request', done => { test('should complete upon successful request', async () => {
const complete = vi.fn(done); const request$ = spectator.service.request({ method: HttpMethod.GET, url: '/test' });
spectator.service.request({ method: HttpMethod.GET, url: '/test' }).subscribe({ complete }); // Create a promise that resolves when the observable completes
const completionPromise = new Promise<void>((resolve, reject) => {
request$.subscribe({
complete: () => resolve(),
error: err => reject(err),
});
});
const req = spectator.expectOne(api + '/test', HttpMethod.GET); const req = spectator.expectOne(api + '/test', HttpMethod.GET);
spectator.flushAll([req], [{}]); spectator.flushAll([req], [{}]);
await completionPromise;
}); });
test('should handle the error', () => { test('should handle the error', () => {

84
npm/ng-packs/packages/core/src/lib/tests/show-password-directive.spec.ts

@ -1,55 +1,63 @@
import { Component, DebugElement } from '@angular/core' import { Component, DebugElement, ChangeDetectorRef } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing' import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ShowPasswordDirective } from '../directives';
import { By } from '@angular/platform-browser'; import { By } from '@angular/platform-browser';
import { ShowPasswordDirective } from '../directives';
@Component({ @Component({
standalone:true, template: ` <input [abpShowPassword]="true" />
template: ` <input [abpShowPassword]="false" />
<input [abpShowPassword]="true"> <input />
<input [abpShowPassword]="false"> <input [abpShowPassword]="showPassword" />`,
<input /> imports: [ShowPasswordDirective],
<input [abpShowPassword]="showPassword" />`,
imports:[ShowPasswordDirective]
}) })
class TestComponent { class TestComponent {
showPassword = false showPassword = false;
} }
describe('ShowPasswordDirective',()=>{ describe('ShowPasswordDirective', () => {
let fixture: ComponentFixture<TestComponent>;; let fixture: ComponentFixture<TestComponent>;
let des : DebugElement[]; let des: DebugElement[];
let desAll : DebugElement[]; let desAll: DebugElement[];
let bareInput; let bareInput;
beforeEach(()=>{ beforeEach(() => {
fixture = TestBed.configureTestingModule({ fixture = TestBed.configureTestingModule({
imports: [ TestComponent ] imports: [TestComponent],
}).createComponent(TestComponent) }).createComponent(TestComponent);
fixture.detectChanges(); fixture.detectChanges();
des = fixture.debugElement.queryAll(By.directive(ShowPasswordDirective)); des = fixture.debugElement.queryAll(By.directive(ShowPasswordDirective));
desAll = fixture.debugElement.queryAll(By.all()); desAll = fixture.debugElement.queryAll(By.all());
bareInput = fixture.debugElement.query(By.css('input:not([abpShowPassword])')); bareInput = fixture.debugElement.query(By.css('input:not([abpShowPassword])'));
}) });
it('should have three input has ShowPasswordDirective elements', () => { it('should have three input has ShowPasswordDirective elements', () => {
expect(des.length).toBe(3); expect(des.length).toBe(3);
}); });
test.each([[0,'text'],[1,'password'],[2,'text'],[3,'password']])('%p. input type must be %p)', (index,inpType) => { test.each([
const inputType = desAll[index].nativeElement.type; [0, 'text'],
expect(inputType).toBe(inpType); [1, 'password'],
}); [2, 'text'],
[3, 'password'],
it('should have three input has ShowPasswordDirective elements', () => { ])('%p. input type must be %p)', (index, inpType) => {
const input = des[2].nativeElement const inputType = desAll[index].nativeElement.type;
expect(input.type).toBe('password') expect(inputType).toBe(inpType);
fixture.componentInstance.showPassword = true });
fixture.detectChanges()
expect(input.type).toBe('text') it('should toggle input type when showPassword changes', () => {
}); const input = des[2].nativeElement;
}); expect(input.type).toBe('password');
fixture.componentInstance.showPassword = true;
const cdr = fixture.componentRef.injector.get(ChangeDetectorRef);
cdr.markForCheck();
cdr.detectChanges();
expect(input.type).toBe('text');
});
});

3
npm/ng-packs/packages/core/src/lib/tests/stop-propagation.directive.spec.ts

@ -28,12 +28,11 @@ describe('StopPropagationDirective', () => {
expect(directive).toBeTruthy(); expect(directive).toBeTruthy();
}); });
test('should not call click event of parent when child element is clicked', done => { test('should not call click event of parent when child element is clicked', () => {
spectator.setHostInput({ parentClickEventFn, childClickEventFn }); spectator.setHostInput({ parentClickEventFn, childClickEventFn });
spectator.click('a'); spectator.click('a');
spectator.detectChanges(); spectator.detectChanges();
expect(childClickEventFn).toHaveBeenCalled(); expect(childClickEventFn).toHaveBeenCalled();
expect(parentClickEventFn).not.toHaveBeenCalled(); expect(parentClickEventFn).not.toHaveBeenCalled();
done();
}); });
}); });

11
npm/ng-packs/packages/core/src/test-setup.ts

@ -1,18 +1,11 @@
import 'zone.js'; import 'zone.js';
import 'zone.js/testing'; import 'zone.js/testing';
import { getTestBed } from '@angular/core/testing'; import { getTestBed } from '@angular/core/testing';
import { import { BrowserTestingModule, platformBrowserTesting } from '@angular/platform-browser/testing';
BrowserDynamicTestingModule,
platformBrowserDynamicTesting,
} from '@angular/platform-browser-dynamic/testing';
// Initialize Angular testing environment // Initialize Angular testing environment
getTestBed().initTestEnvironment( getTestBed().initTestEnvironment(BrowserTestingModule, platformBrowserTesting());
BrowserDynamicTestingModule,
platformBrowserDynamicTesting(),
);
// Mock window.location for test environment
Object.defineProperty(window, 'location', { Object.defineProperty(window, 'location', {
value: { value: {
href: 'http://localhost:4200', href: 'http://localhost:4200',

Loading…
Cancel
Save