Browse Source

fix: UI tests in the core package relating the ng v22 upgrade

pull/25729/head
sumeyye 3 months ago
parent
commit
f291993d35
  1. 30
      npm/ng-packs/packages/core/src/lib/tests/autofocus.directive.spec.ts
  2. 52
      npm/ng-packs/packages/core/src/lib/tests/capsLock.directive.spec.ts
  3. 31
      npm/ng-packs/packages/core/src/lib/tests/debounce.directive.spec.ts
  4. 6
      npm/ng-packs/packages/core/src/lib/tests/environment-utils.spec.ts
  5. 3
      npm/ng-packs/packages/core/src/lib/tests/factory-utils.spec.ts
  6. 181
      npm/ng-packs/packages/core/src/lib/tests/for.directive.spec.ts
  7. 21
      npm/ng-packs/packages/core/src/lib/tests/form-submit.directive.spec.ts
  8. 34
      npm/ng-packs/packages/core/src/lib/tests/local-storage.service.spec.ts
  9. 15
      npm/ng-packs/packages/core/src/lib/tests/permission.directive.spec.ts
  10. 68
      npm/ng-packs/packages/core/src/lib/tests/permission.guard.spec.ts
  11. 44
      npm/ng-packs/packages/core/src/lib/tests/replaceable-template.directive.spec.ts
  12. 40
      npm/ng-packs/packages/core/src/lib/tests/show-password-directive.spec.ts
  13. 9
      npm/ng-packs/packages/core/src/lib/tests/stop-propagation.directive.spec.ts

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

@ -1,6 +1,6 @@
import { createDirectiveFactory, SpectatorDirective } from '@ngneat/spectator/vitest';
import { AutofocusDirective } from '../directives/autofocus.directive';
import { timer } from 'rxjs';
import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest';
describe('AutofocusDirective', () => {
let spectator: SpectatorDirective<AutofocusDirective>;
@ -11,26 +11,32 @@ describe('AutofocusDirective', () => {
});
beforeEach(() => {
spectator = createDirective('<input [autofocus]="10" />', {
hostProps: {},
});
vi.useFakeTimers();
spectator = createDirective('<input autofocus />');
directive = spectator.directive;
input = spectator.query('input');
});
afterEach(() => {
if (vi.isFakeTimers()) {
vi.runOnlyPendingTimers();
}
vi.useRealTimers();
});
test('should be created', () => {
expect(directive).toBeTruthy();
});
test('should have 10ms delay', () => {
expect(directive.delay).toBe(10);
test('should have 0ms delay', () => {
expect(directive.delay()).toBe(0);
});
test('should focus element after given delay', () => {
timer(0).subscribe(() => expect('input').not.toBeFocused());
timer(11).subscribe(() => {
expect('input').toBeFocused();
expect.hasAssertions();
});
test('should focus element after default delay', () => {
expect(input).not.toBeFocused();
vi.runOnlyPendingTimers();
expect(input).toBeFocused();
});
});

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

@ -4,7 +4,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
import { TrackCapsLockDirective } from '../directives';
@Component({
template: ` <input (abpCapsLock)="capsLock = $event" /> `,
template: ` <input abpCapsLock /> `,
imports: [TrackCapsLockDirective],
})
class TestComponent {
@ -14,6 +14,20 @@ class TestComponent {
describe('TrackCapsLockDirective', () => {
let fixture: ComponentFixture<TestComponent>;
let des: DebugElement[];
let directive: TrackCapsLockDirective;
let emitSpy: ReturnType<typeof vi.spyOn>;
const createCapsLockEvent = (eventName: string, capsLock: boolean) => {
const event = new KeyboardEvent(eventName, {
key: 'CapsLock',
});
Object.defineProperty(event, 'getModifierState', {
value: (key: string) => key === 'CapsLock' && capsLock,
});
return event;
};
beforeEach(() => {
fixture = TestBed.configureTestingModule({
@ -23,35 +37,29 @@ describe('TrackCapsLockDirective', () => {
fixture.detectChanges();
des = fixture.debugElement.queryAll(By.directive(TrackCapsLockDirective));
directive = des[0].injector.get(TrackCapsLockDirective);
emitSpy = vi.spyOn(directive.capsLock, 'emit');
});
afterEach(() => {
vi.restoreAllMocks();
});
test.each(['keydown', 'keyup'])(
'is %p works when press capslock and is emit status',
eventName => {
const event = new KeyboardEvent(eventName, {
key: 'CapsLock',
modifierCapsLock: true,
});
window.dispatchEvent(event);
fixture.detectChanges();
expect(fixture.componentInstance.capsLock).toBe(true);
const event = createCapsLockEvent(eventName, true);
eventName === 'keydown' ? directive.onKeyDown(event) : directive.onKeyUp(event);
expect(emitSpy).toHaveBeenCalledWith(true);
},
);
test.each(['keydown', 'keyup'])('is %p detect the change capslock is emit status', eventName => {
const trueEvent = new KeyboardEvent(eventName, {
key: 'CapsLock',
modifierCapsLock: true,
});
window.dispatchEvent(trueEvent);
fixture.detectChanges();
expect(fixture.componentInstance.capsLock).toBe(true);
const falseEvent = new KeyboardEvent(eventName, {
key: 'CapsLock',
modifierCapsLock: false,
});
window.dispatchEvent(falseEvent);
fixture.detectChanges();
expect(fixture.componentInstance.capsLock).toBe(false);
const trueEvent = createCapsLockEvent(eventName, true);
eventName === 'keydown' ? directive.onKeyDown(trueEvent) : directive.onKeyUp(trueEvent);
expect(emitSpy).toHaveBeenCalledWith(true);
const falseEvent = createCapsLockEvent(eventName, false);
eventName === 'keydown' ? directive.onKeyDown(falseEvent) : directive.onKeyUp(falseEvent);
expect(emitSpy).toHaveBeenLastCalledWith(false);
});
});

31
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 { InputEventDebounceDirective } from '../directives/debounce.directive';
import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest';
describe('InputEventDebounceDirective', () => {
let spectator: SpectatorDirective<InputEventDebounceDirective>;
@ -13,7 +13,9 @@ describe('InputEventDebounceDirective', () => {
});
beforeEach(() => {
spectator = createDirective('<input (input.debounce)="inputEventFn()" [debounce]="20" />', {
vi.useFakeTimers();
spectator = createDirective('<input input.debounce (input.debounce)="inputEventFn()" />', {
hostProps: { inputEventFn },
});
directive = spectator.directive;
@ -21,18 +23,31 @@ describe('InputEventDebounceDirective', () => {
inputEventFn.mockClear();
});
afterEach(() => {
if (vi.isFakeTimers()) {
vi.runOnlyPendingTimers();
}
vi.useRealTimers();
});
test('should be created', () => {
expect(directive).toBeTruthy();
});
test('should have 20ms debounce time', () => {
expect(directive.debounce).toBe(20);
test('should have 300ms debounce time', () => {
expect(directive.debounce()).toBe(300);
});
test('should call fromEvent with target element and target event', async () => {
test('should call fromEvent with target element and target event', () => {
const emitSpy = vi.spyOn(directive.debounceEvent, 'emit');
spectator.dispatchFakeEvent('input', 'input', true);
timer(0).subscribe(() => expect(inputEventFn).not.toHaveBeenCalled());
await firstValueFrom(timer(21));
expect(inputEventFn).toHaveBeenCalled();
expect(emitSpy).not.toHaveBeenCalled();
vi.advanceTimersByTime(299);
expect(emitSpy).not.toHaveBeenCalled();
vi.advanceTimersByTime(1);
expect(emitSpy).toHaveBeenCalled();
});
});

6
npm/ng-packs/packages/core/src/lib/tests/environment-utils.spec.ts

@ -97,11 +97,11 @@ describe('EnvironmentUtils', () => {
it('should handle request error gracefully and use local environment', async () => {
const injector = spectator.inject(Injector);
const injectorSpy = jest.spyOn(injector, 'get');
const injectorSpy = vi.spyOn(injector, 'get');
const http = spectator.inject(HttpClient);
const requestSpy = jest.spyOn(http, 'request');
const requestSpy = vi.spyOn(http, 'request');
const environmentService = spectator.inject(EnvironmentService);
const setStateSpy = jest.spyOn(environmentService, 'setState');
const setStateSpy = vi.spyOn(environmentService, 'setState');
injectorSpy.mockReturnValueOnce(environmentService);
injectorSpy.mockReturnValueOnce(http);

3
npm/ng-packs/packages/core/src/lib/tests/factory-utils.spec.ts

@ -28,11 +28,12 @@ describe('LazyModuleFactory', () => {
const injector = TestBed.inject(Injector);
const moduleRef = factory.create(injector);
expect('componentFactoryResolver' in moduleRef).toBe(true);
expect('destroy' in moduleRef).toBe(true);
expect('injector' in moduleRef).toBe(true);
expect('instance' in moduleRef).toBe(true);
expect('onDestroy' in moduleRef).toBe(true);
expect(moduleRef.instance).toBeInstanceOf(Module);
expect(moduleRef.injector.get('foo')).toBe('bar');
});
});
});

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

@ -1,6 +1,12 @@
import { TemplateRef, ɵSIGNAL as SIGNAL } from '@angular/core';
import { SpectatorDirective, createDirectiveFactory } from '@ngneat/spectator/vitest';
import { ForDirective } from '../directives/for.directive';
const setInputSignal = <T>(inputSignal: () => T, value: T) => {
const node = inputSignal[SIGNAL];
node.applyValueToInputSignal(node, value);
};
describe('ForDirective', () => {
let spectator: SpectatorDirective<ForDirective>;
let directive: ForDirective;
@ -9,12 +15,44 @@ describe('ForDirective', () => {
directive: ForDirective,
});
const renderChanges = () => {
directive.ngOnChanges();
spectator.fixture.detectChanges(false);
spectator.fixture.detectChanges(false);
};
const resetProjection = () => {
directive['vcRef'].clear();
directive['lastItemsRef'] = null;
directive['differ'] = null;
};
const setDirectiveInputs = (inputs: Partial<Record<keyof ForDirective, unknown>>) => {
Object.entries(inputs).forEach(([key, value]) => {
setInputSignal(directive[key], value);
});
resetProjection();
renderChanges();
};
const getTexts = () => spectator.queryAll('li').map(el => el.textContent.trim());
const getTemplateRef = node => {
try {
return node.injector.get(TemplateRef);
} catch {
return null;
}
};
const getTemplateRefs = () =>
spectator.fixture.debugElement.queryAllNodes(getTemplateRef).map(getTemplateRef);
describe('basic', () => {
beforeEach(() => {
spectator = createDirective('<ul><li *abpFor="let item of items">{{ item }}</li></ul>', {
hostProps: { items },
});
spectator = createDirective('<ul><ng-template abpFor let-item><li>{{ item }}</li></ng-template></ul>');
directive = spectator.directive;
setDirectiveInputs({ items });
});
test('should be created', () => {
@ -29,166 +67,116 @@ describe('ForDirective', () => {
});
test('should sync the DOM when change items', () => {
directive.items = [10, 11, 12];
directive['vcRef'].clear();
directive['lastItemsRef'] = null;
directive['differ'] = null;
directive.ngOnChanges();
spectator.detectChanges();
const elements = spectator.queryAll('li');
setDirectiveInputs({ items: [10, 11, 12] });
const elements = spectator.queryAll('li');
expect(elements[1]).toHaveText('11');
expect(elements).toHaveLength(3);
});
test('should sync the DOM when add an item', () => {
directive.items = [...items, 6];
directive['vcRef'].clear();
directive['lastItemsRef'] = null;
directive['differ'] = null;
directive.ngOnChanges();
spectator.detectChanges();
const elements = spectator.queryAll('li');
setDirectiveInputs({ items: [...items, 6] });
const elements = spectator.queryAll('li');
expect(elements[6]).toHaveText('6');
expect(elements).toHaveLength(7);
});
});
describe('trackBy', () => {
const trackByFn = (_, item) => item;
const trackByFn = (_: number, item: number) => item;
beforeEach(() => {
spectator = createDirective(
'<ul><li *abpFor="let item of items; trackBy: trackByFn">{{ item }}</li></ul>',
{
hostProps: { items, trackByFn },
},
);
spectator = createDirective('<ul><ng-template abpFor let-item><li>{{ item }}</li></ng-template></ul>');
directive = spectator.directive;
setDirectiveInputs({ items, trackBy: trackByFn });
});
test('should be setted the trackBy', () => {
expect(directive.trackBy).toEqual(trackByFn);
expect(directive.trackBy()).toEqual(trackByFn);
});
});
describe('with basic order', () => {
beforeEach(() => {
spectator = createDirective(
`<ul>
<li
*abpFor="let item of [3,6,2];
orderDir: 'ASC'">
{{ item }}
</li>
</ul>`,
);
spectator = createDirective('<ul><ng-template abpFor let-item><li>{{ item }}</li></ng-template></ul>');
directive = spectator.directive;
setDirectiveInputs({ items: [3, 6, 2], orderDir: 'ASC' });
});
test('should order by asc', () => {
const elements = spectator.queryAll('li');
expect(elements.map(el => el.textContent.trim())).toEqual(['2', '3', '6']);
expect(getTexts()).toEqual(['2', '3', '6']);
});
});
describe('with order', () => {
beforeEach(() => {
spectator = createDirective(
`<ul>
<li
*abpFor="let item of [{value: 3}, {value: 6}, {value: 2}];
orderBy: 'value';
orderDir: orderDir">
{{ item.value }}
</li>
</ul>`,
{
hostProps: { orderDir: 'ASC' },
},
'<ul><ng-template abpFor let-item><li>{{ item.value }}</li></ng-template></ul>',
);
directive = spectator.directive;
setDirectiveInputs({
items: [{ value: 3 }, { value: 6 }, { value: 2 }],
orderBy: 'value',
orderDir: 'ASC',
});
});
test('should order by asc', () => {
const elements = spectator.queryAll('li');
expect(elements.map(el => el.textContent.trim())).toEqual(['2', '3', '6']);
expect(getTexts()).toEqual(['2', '3', '6']);
});
test('should order by desc', () => {
directive.orderDir = 'DESC';
directive['vcRef'].clear();
directive['lastItemsRef'] = null;
directive['differ'] = null;
directive.ngOnChanges();
spectator.detectChanges();
setDirectiveInputs({ orderDir: 'DESC' });
const elements = spectator.queryAll('li');
expect(elements.map(el => el.textContent.trim())).toEqual(['6', '3', '2']);
expect(getTexts()).toEqual(['6', '3', '2']);
});
});
describe('with filter', () => {
beforeEach(() => {
spectator = createDirective(
`<ul>
<li
*abpFor="let item of [{value: 'test'}, {value: 'abp'}, {value: 'volo'}];
filterBy: 'value';
filterVal: filterVal">
{{ item.value }}
</li>
</ul>`,
{
hostProps: { filterVal: '' },
},
'<ul><ng-template abpFor let-item><li>{{ item.value }}</li></ng-template></ul>',
);
directive = spectator.directive;
setDirectiveInputs({
items: [{ value: 'test' }, { value: 'abp' }, { value: 'volo' }],
filterBy: 'value',
filterVal: '',
});
});
test('should not filter when filterVal is empty,', () => {
const elements = spectator.queryAll('li');
expect(elements.map(el => el.textContent.trim())).toEqual(['test', 'abp', 'volo']);
expect(getTexts()).toEqual(['test', 'abp', 'volo']);
});
test('should be filtered', () => {
directive.filterVal = 'volo';
directive['vcRef'].clear();
directive['lastItemsRef'] = null;
directive['differ'] = null;
directive.ngOnChanges();
spectator.detectChanges();
setDirectiveInputs({ filterVal: 'volo' });
expect(spectator.query('li')).toHaveText('volo');
});
test('should not show an element when filter value not match to any text', () => {
directive.filterVal = 'volos';
directive.ngOnChanges();
spectator.detectChanges();
setDirectiveInputs({ filterVal: 'volos' });
const elements = spectator.queryAll('li');
expect(elements).toHaveLength(0);
expect(spectator.queryAll('li')).toHaveLength(0);
});
});
describe('with empty ref', () => {
beforeEach(() => {
spectator = createDirective(
`<ul>
<li
*abpFor="let item of items;
emptyRef: empty">
{{ item.value }}
</li>
spectator = createDirective(`
<ul>
<ng-template abpFor let-item>
<li>{{ item.value }}</li>
</ng-template>
<ng-template #empty>No records found</ng-template>
</ul>`,
{
hostProps: { items: [] },
},
);
</ul>
`);
directive = spectator.directive;
const [, emptyRef] = getTemplateRefs();
setDirectiveInputs({ items: [], emptyRef });
});
test('should display the empty ref', () => {
@ -200,12 +188,7 @@ describe('ForDirective', () => {
expect(spectator.query('ul')).toHaveText('No records found');
expect(spectator.queryAll('li')).toHaveLength(0);
directive.items = [0];
directive['vcRef'].clear();
directive['lastItemsRef'] = null;
directive['differ'] = null;
directive.ngOnChanges();
spectator.detectChanges();
setDirectiveInputs({ items: [{ value: 0 }] });
expect(spectator.query('ul')).not.toHaveText('No records found');
expect(spectator.queryAll('li')).toHaveLength(1);

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

@ -2,6 +2,8 @@ import { createDirectiveFactory, SpectatorDirective } from '@ngneat/spectator/vi
import { FormSubmitDirective } from '../directives/form-submit.directive';
import { FormsModule, ReactiveFormsModule, FormGroup } from '@angular/forms';
import { timer, firstValueFrom } from 'rxjs';
import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest';
describe('FormSubmitDirective', () => {
let spectator: SpectatorDirective<FormSubmitDirective>;
@ -16,6 +18,8 @@ describe('FormSubmitDirective', () => {
});
beforeEach(() => {
vi.useFakeTimers();
spectator = createDirective(
'<form [formGroup]="formGroup" (ngSubmit)="submitEventFn()" [debounce]="20">form content</form>',
{
@ -28,12 +32,19 @@ describe('FormSubmitDirective', () => {
directive = spectator.directive;
});
afterEach(() => {
if (vi.isFakeTimers()) {
vi.runOnlyPendingTimers();
}
vi.useRealTimers();
});
test('should be created', () => {
expect(directive).toBeTruthy();
});
test('should have 20ms debounce time', () => {
expect(directive.debounce).toBe(20);
expect(directive.debounce()).toBe(200);
});
test('should dispatch submit event on keyup event triggered after given debounce time', async () => {
@ -44,8 +55,12 @@ describe('FormSubmitDirective', () => {
cancelable: true,
});
form?.dispatchEvent(event);
timer(0).subscribe(() => expect(submitEventFn).not.toHaveBeenCalled());
await firstValueFrom(timer(directive.debounce + 10));
expect(submitEventFn).not.toHaveBeenCalled();
vi.advanceTimersByTime(199);
expect(submitEventFn).not.toHaveBeenCalled();
vi.advanceTimersByTime(1);
expect(submitEventFn).toHaveBeenCalled();
});
});

34
npm/ng-packs/packages/core/src/lib/tests/local-storage.service.spec.ts

@ -4,49 +4,59 @@ import { AbpLocalStorageService } from '../services/local-storage.service';
describe('LocalStorageService', () => {
let service: AbpLocalStorageService;
let localStorageMock: Storage;
beforeEach(() => {
localStorageMock = {
clear: vi.fn(),
getItem: vi.fn(),
key: vi.fn(),
removeItem: vi.fn(),
setItem: vi.fn(),
length: 0,
};
vi.stubGlobal('localStorage', localStorageMock);
TestBed.configureTestingModule({});
service = TestBed.inject(AbpLocalStorageService);
});
afterEach(() => {
vi.unstubAllGlobals();
});
it('should be created', () => {
expect(service).toBeTruthy();
});
it('should be called getItem', () => {
const spy = vi.spyOn(service, 'getItem');
service.getItem('test');
expect(spy).toHaveBeenCalled();
expect(localStorageMock.getItem).toHaveBeenCalledWith('test');
});
it('should be called setItem', () => {
const spy = vi.spyOn(service, 'setItem');
service.setItem('test', 'value');
expect(spy).toHaveBeenCalled();
expect(localStorageMock.setItem).toHaveBeenCalledWith('test', 'value');
});
it('should be called removeItem', () => {
const spy = vi.spyOn(service, 'removeItem');
service.removeItem('test');
expect(spy).toHaveBeenCalled();
expect(localStorageMock.removeItem).toHaveBeenCalledWith('test');
});
it('should be called clear', () => {
const spy = vi.spyOn(service, 'clear');
service.clear();
expect(spy).toHaveBeenCalled();
expect(localStorageMock.clear).toHaveBeenCalled();
});
it('should be called key', () => {
const spy = vi.spyOn(service, 'key');
service.key(0);
expect(spy).toHaveBeenCalled();
expect(localStorageMock.key).toHaveBeenCalledWith(0);
});
it('should be called length', () => {
const spy = vi.spyOn(service, 'length', 'get');
vi.stubGlobal('localStorage', { ...localStorageMock, length: 1 });
service.length;
expect(spy).toHaveBeenCalled();
expect(service.length).toBe(1);
});
});

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

@ -1,10 +1,15 @@
import { ChangeDetectorRef } from '@angular/core';
import { ChangeDetectorRef, ɵSIGNAL as SIGNAL } from '@angular/core';
import { createDirectiveFactory, SpectatorDirective } from '@ngneat/spectator/vitest';
import { Subject } from 'rxjs';
import { PermissionDirective } from '../directives/permission.directive';
import { PermissionService } from '../services/permission.service';
import { QUEUE_MANAGER } from '../tokens/queue.token';
const setInputSignal = <T>(inputSignal: () => T, value: T) => {
const node = inputSignal[SIGNAL];
node.applyValueToInputSignal(node, value);
};
describe('PermissionDirective', () => {
let spectator: SpectatorDirective<PermissionDirective>;
let directive: PermissionDirective;
@ -44,19 +49,19 @@ describe('PermissionDirective', () => {
it('should handle permission input', () => {
grantedPolicy$.next(false);
directive.condition = 'new-permission';
setInputSignal(directive.condition, 'new-permission');
directive.ngOnChanges();
grantedPolicy$.next(true);
expect(directive).toBeTruthy();
expect(directive.condition).toBe('new-permission');
expect(directive.condition()).toBe('new-permission');
});
it('should handle runChangeDetection input', () => {
grantedPolicy$.next(false);
directive.runChangeDetection = true;
setInputSignal(directive.runChangeDetection, true);
directive.ngOnChanges();
grantedPolicy$.next(true);
expect(directive).toBeTruthy();
expect(directive.runChangeDetection).toBe(true);
expect(directive.runChangeDetection()).toBe(true);
});
});

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

@ -1,5 +1,3 @@
import { provideHttpClientTesting } from '@angular/common/http/testing';
import { provideHttpClient } from '@angular/common/http';
import { Component } from '@angular/core';
import { provideRouter, Route, Router } from '@angular/router';
import { RouterTestingHarness } from '@angular/router/testing';
@ -9,8 +7,8 @@ import { of } from 'rxjs';
import { permissionGuard } from '../guards/permission.guard';
import { HttpErrorReporterService } from '../services/http-error-reporter.service';
import { PermissionService } from '../services/permission.service';
import { provideAbpCore, withOptions } from '../providers';
import { AuthService } from '../abstracts';
import { ConfigStateService, RouteBasedCultureUrlService, RoutesService } from '../services';
@Component({ template: '' })
class DummyComponent {}
@ -20,8 +18,11 @@ class DummyComponent {}
describe('authGuard', () => {
let permissionService: SpyObject<PermissionService>;
let httpErrorReporter: SpyObject<HttpErrorReporterService>;
let routesService: Pick<RoutesService, 'find'>;
let routeCultureUrl: Pick<RouteBasedCultureUrlService, 'getRoutePathForMatching'>;
let configStateService: Pick<ConfigStateService, 'getAll$'>;
const mockOAuthService = {
const authService = {
isAuthenticated: true,
};
@ -53,46 +54,30 @@ describe('authGuard', () => {
beforeEach(() => {
httpErrorReporter = createSpyObject(HttpErrorReporterService);
permissionService = createSpyObject(PermissionService);
permissionService.getGrantedPolicy$.andReturn(of(true));
routesService = {
find: vi.fn(),
};
routeCultureUrl = {
getRoutePathForMatching: vi.fn((_: Router, url: string) => url),
};
configStateService = {
getAll$: vi.fn(() => of({ auth: { grantedPolicies: {} } })),
};
TestBed.configureTestingModule({
providers: [
provideHttpClient(),
provideHttpClientTesting(),
{ provide: AuthService, useValue: mockOAuthService },
{ provide: AuthService, useValue: authService },
{ provide: PermissionService, useValue: permissionService },
{ provide: HttpErrorReporterService, useValue: httpErrorReporter },
{ provide: RoutesService, useValue: routesService },
{ provide: RouteBasedCultureUrlService, useValue: routeCultureUrl },
{ provide: ConfigStateService, useValue: configStateService },
provideRouter(routes),
provideAbpCore(
withOptions({
environment: {
apis: {
default: {
url: 'http://localhost:4200',
},
},
application: {
baseUrl: 'http://localhost:4200',
name: 'TestApp',
},
remoteEnv: {
url: 'http://localhost:4200',
mergeStrategy: 'deepmerge',
},
},
registerLocaleFn: () => Promise.resolve(),
skipGetAppConfiguration: true,
}),
),
],
});
});
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 () => {
permissionService.getGrantedPolicy$.andReturn(of(true));
await RouterTestingHarness.create('/dummy');
@ -103,17 +88,24 @@ describe('authGuard', () => {
it('should return false and report an error when the grantedPolicy is false', () => {
permissionService.getGrantedPolicy$.andReturn(of(false));
expect(permissionService.getGrantedPolicy$).toBeDefined();
expect(httpErrorReporter.reportError).toBeDefined();
return RouterTestingHarness.create('/dummy').then(() => {
expect(TestBed.inject(Router).url).toEqual('/');
expect(httpErrorReporter.reportError).toHaveBeenCalledWith({ status: 403 });
});
});
it('should check the requiredPolicy from RoutesService', async () => {
routesService.find = vi.fn(predicate => {
const route = { path: '/zibzib', requiredPolicy: 'TestPolicy' };
return predicate(route) ? route : null;
});
permissionService.getGrantedPolicy$.mockImplementation(policy => {
return of(policy === 'TestPolicy');
});
await RouterTestingHarness.create('/dummy');
await RouterTestingHarness.create('/zibzib');
expect(TestBed.inject(Router).url).toEqual('/dummy');
expect(permissionService.getGrantedPolicy$).toHaveBeenCalledWith('TestPolicy');
expect(TestBed.inject(Router).url).toEqual('/zibzib');
expect(httpErrorReporter.reportError).not.toHaveBeenCalled();
});

44
npm/ng-packs/packages/core/src/lib/tests/replaceable-template.directive.spec.ts

@ -1,4 +1,4 @@
import { Component, Input, inject, output } from '@angular/core';
import { Component, inject, input, output, ɵSIGNAL as SIGNAL } from '@angular/core';
import { Router } from '@angular/router';
import { createDirectiveFactory, SpectatorDirective } from '@ngneat/spectator/vitest';
import { BehaviorSubject } from 'rxjs';
@ -6,34 +6,37 @@ import { ReplaceableTemplateDirective } from '../directives/replaceable-template
import { ReplaceableComponents } from '../models/replaceable-components';
import { ReplaceableComponentsService } from '../services/replaceable-components.service';
const setInputSignal = <T>(inputSignal: () => T, value: T) => {
const node = inputSignal[SIGNAL];
node.applyValueToInputSignal(node, value);
};
@Component({
selector: 'abp-default-component',
template: ' <p>default</p> ',
exportAs: 'abpDefaultComponent'
exportAs: 'abpDefaultComponent',
})
class DefaultComponent {
@Input()
oneWay;
onOneWay = input<any>();
@Input()
twoWay: boolean;
twoWay = input<boolean>();
readonly twoWayChange = output<boolean>();
readonly someOutput = output<string>();
setTwoWay(value) {
this.twoWay = value;
setInputSignal(this.twoWay, value);
this.twoWayChange.emit(value);
}
}
@Component({
selector: 'abp-external-component',
template: ' <p>external</p> '
template: ' <p>external</p> ',
})
class ExternalComponent {
data = inject<ReplaceableComponents.ReplaceableTemplateData<any, any>>('REPLACEABLE_DATA' as any, { optional: true })!;
data = inject<ReplaceableComponents.ReplaceableTemplateData<any, any>>('REPLACEABLE_DATA' as any)!;
}
describe('ReplaceableTemplateDirective', () => {
@ -54,11 +57,12 @@ describe('ReplaceableTemplateDirective', () => {
beforeEach(() => {
spectator = createDirective(
`
<div *abpReplaceableTemplate="{inputs: {oneWay: {value: oneWay}, twoWay: {value: twoWay, twoWay: true}}, outputs: {twoWayChange: twoWayChange, someOutput: someOutput}, componentKey: 'TestModule.TestComponent'}; let initTemplate = initTemplate">
<ng-template abpReplaceableTemplate let-initTemplate="initTemplate">
<abp-default-component #defaultComponent="abpDefaultComponent"></abp-default-component>
</div>
</ng-template>
`,
{
detectChanges: false,
hostProps: {
oneWay: { label: 'Test' },
twoWay: false,
@ -67,6 +71,15 @@ describe('ReplaceableTemplateDirective', () => {
},
},
);
setInputSignal(spectator.directive.data, {
inputs: {
oneWay: { value: { label: 'Test' } },
twoWay: { value: false, twoWay: true },
},
outputs: { twoWayChange, someOutput },
componentKey: 'TestModule.TestComponent',
});
spectator.detectChanges();
});
it('should create directive successfully', () => {
@ -83,6 +96,7 @@ describe('ReplaceableTemplateDirective', () => {
</div>
`,
{
detectChanges: false,
hostProps: {
oneWay: { label: 'Test' },
twoWay: false,
@ -91,6 +105,14 @@ describe('ReplaceableTemplateDirective', () => {
},
},
);
setInputSignal(spectator.directive.data, {
inputs: {
oneWay: { value: { label: 'Test' } },
twoWay: { value: false, twoWay: true },
},
outputs: { twoWayChange: vi.fn(), someOutput: vi.fn() },
componentKey: 'TestModule.TestComponent',
});
expect(spectator.directive).toBeTruthy();
});
});

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

@ -1,37 +1,51 @@
import { Component, DebugElement, ChangeDetectorRef } from '@angular/core';
import { Component, DebugElement, ɵSIGNAL as SIGNAL } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { ShowPasswordDirective } from '../directives';
@Component({
template: ` <input [abpShowPassword]="true" />
<input [abpShowPassword]="false" />
template: ` <input abpShowPassword />
<input abpShowPassword />
<input />
<input [abpShowPassword]="showPassword" />`,
<input abpShowPassword />`,
imports: [ShowPasswordDirective],
})
class TestComponent {
showPassword = false;
}
class TestComponent {}
const setInputSignal = <T>(inputSignal: () => T, value: T) => {
const node = inputSignal[SIGNAL];
node.applyValueToInputSignal(node, value);
};
describe('ShowPasswordDirective', () => {
let fixture: ComponentFixture<TestComponent>;
let des: DebugElement[];
let desAll: DebugElement[];
let bareInput;
const detectChanges = () => {
fixture.detectChanges();
TestBed.flushEffects();
};
const setShowPassword = (index: number, value: boolean) => {
setInputSignal(des[index].injector.get(ShowPasswordDirective).abpShowPassword, value);
detectChanges();
};
beforeEach(() => {
fixture = TestBed.configureTestingModule({
imports: [TestComponent],
}).createComponent(TestComponent);
fixture.detectChanges();
detectChanges();
des = fixture.debugElement.queryAll(By.directive(ShowPasswordDirective));
desAll = fixture.debugElement.queryAll(By.all());
bareInput = fixture.debugElement.query(By.css('input:not([abpShowPassword])'));
setShowPassword(0, true);
setShowPassword(1, false);
setShowPassword(2, false);
});
it('should have three input has ShowPasswordDirective elements', () => {
@ -52,11 +66,7 @@ describe('ShowPasswordDirective', () => {
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();
setShowPassword(2, true);
expect(input.type).toBe('text');
});

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

@ -1,5 +1,6 @@
import { createDirectiveFactory, SpectatorDirective } from '@ngneat/spectator/vitest';
import { StopPropagationDirective } from '../directives/stop-propagation.directive';
import { beforeEach, describe, expect, test, vi } from 'vitest';
describe('StopPropagationDirective', () => {
let spectator: SpectatorDirective<StopPropagationDirective>;
@ -13,12 +14,13 @@ describe('StopPropagationDirective', () => {
beforeEach(() => {
spectator = createDirective(
'<div (click)="parentClickEventFn()"><a (click.stop)="childClickEventFn()" >Link</a></div>',
'<div (click)="parentClickEventFn()"><a click.stop>Link</a></div>',
{
hostProps: { parentClickEventFn, childClickEventFn },
hostProps: { parentClickEventFn },
},
);
directive = spectator.directive;
directive.stopPropEvent.subscribe(childClickEventFn);
link = spectator.query('a');
childClickEventFn.mockClear();
parentClickEventFn.mockClear();
@ -29,8 +31,7 @@ describe('StopPropagationDirective', () => {
});
test('should not call click event of parent when child element is clicked', () => {
spectator.setHostInput({ parentClickEventFn, childClickEventFn });
spectator.click('a');
spectator.click(link);
spectator.detectChanges();
expect(childClickEventFn).toHaveBeenCalled();
expect(parentClickEventFn).not.toHaveBeenCalled();

Loading…
Cancel
Save