Skip to content

Commit 44d2a25

Browse files
Copilotrenemadsen
andcommitted
Add karma unit testing infrastructure and initial spec files for units and workers components
Co-authored-by: renemadsen <[email protected]>
1 parent 6afc613 commit 44d2a25

File tree

11 files changed

+1275
-36
lines changed

11 files changed

+1275
-36
lines changed

eform-client/package.json

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
},
6161
"private": false,
6262
"dependencies": {
63+
"@angular-material-extensions/password-strength": "^16.0.0",
6364
"@angular/animations": "20.1.2",
6465
"@angular/cdk": "20.1.2",
6566
"@angular/common": "20.1.2",
@@ -71,7 +72,6 @@
7172
"@angular/platform-browser": "20.1.2",
7273
"@angular/platform-browser-dynamic": "20.1.2",
7374
"@angular/router": "20.1.2",
74-
"@angular-material-extensions/password-strength": "^16.0.0",
7575
"@ng-matero/extensions": "20.2.1",
7676
"@ngrx/effects": "19.2.1",
7777
"@ngrx/entity": "19.2.1",
@@ -93,6 +93,7 @@
9393
"file-saver": "2.0.5",
9494
"glob": "11.0.3",
9595
"hammerjs": "2.0.8",
96+
"luxon": "^3.7.2",
9697
"moment": "2.30.1",
9798
"ng-gallery": "^12.0.0",
9899
"ng2-dragula": "^6.0.0",
@@ -102,6 +103,7 @@
102103
"ngx-cookie-service": "20.1.0",
103104
"ngx-editor": "^18.0.0",
104105
"ngx-mask": "^20.0.3",
106+
"ngx-material-timepicker": "^13.1.1",
105107
"ngx-papaparse": "8.0.0",
106108
"ngx-slimscroll": "12.2.0",
107109
"ngx-toastr": "19.0.0",
@@ -112,10 +114,8 @@
112114
"rxjs": "7.8.2",
113115
"tslib": "^2.8.1",
114116
"uuid": "13.0.0",
115-
"zone.js": "^0.15.1",
116-
"ngx-material-timepicker": "^13.1.1",
117-
"luxon": "^3.7.2",
118-
"validator": "^13.15.15"
117+
"validator": "^13.15.15",
118+
"zone.js": "^0.15.1"
119119
},
120120
"devDependencies": {
121121
"@angular-devkit/build-angular": "20.3.2",
@@ -133,6 +133,7 @@
133133
"@types/d3": "^7.4.3",
134134
"@types/dragula": "^2.1.34",
135135
"@types/file-saver": "^2.0.7",
136+
"@types/jasmine": "^5.1.9",
136137
"@types/mocha": "^10.0.10",
137138
"@types/node": "^24.5.2",
138139
"@types/uuid": "^10.0.0",
@@ -150,6 +151,11 @@
150151
"eslint": "^8.57.1",
151152
"fs-extra": "^11.3.1",
152153
"guid-typescript": "^1.0.9",
154+
"karma": "^6.4.4",
155+
"karma-chrome-launcher": "^3.2.0",
156+
"karma-coverage": "^2.2.1",
157+
"karma-jasmine": "^5.1.0",
158+
"karma-jasmine-html-reporter": "^2.1.0",
153159
"mammoth": "^1.10.0",
154160
"path": "^0.12.7",
155161
"run-sequence": "^2.2.1",
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
2+
import { UnitCreateComponent } from './unit-create.component';
3+
import { UnitsService } from 'src/app/common/services';
4+
import { DeviceUserService } from 'src/app/common/services/device-users';
5+
import { MatDialogRef } from '@angular/material/dialog';
6+
import { of } from 'rxjs';
7+
import { UnitModel, SiteDto, DeviceUserRequestModel, OperationResult, OperationDataResult } from 'src/app/common/models';
8+
9+
describe('UnitCreateComponent', () => {
10+
let component: UnitCreateComponent;
11+
let fixture: ComponentFixture<UnitCreateComponent>;
12+
let mockUnitsService: jasmine.SpyObj<UnitsService>;
13+
let mockDeviceUserService: jasmine.SpyObj<DeviceUserService>;
14+
let mockDialogRef: jasmine.SpyObj<MatDialogRef<UnitCreateComponent>>;
15+
16+
beforeEach(waitForAsync(() => {
17+
mockUnitsService = jasmine.createSpyObj('UnitsService', ['createUnit']);
18+
mockDeviceUserService = jasmine.createSpyObj('DeviceUserService', ['getDeviceUsersFiltered']);
19+
mockDialogRef = jasmine.createSpyObj('MatDialogRef', ['close']);
20+
21+
TestBed.configureTestingModule({
22+
declarations: [UnitCreateComponent],
23+
providers: [
24+
{ provide: UnitsService, useValue: mockUnitsService },
25+
{ provide: DeviceUserService, useValue: mockDeviceUserService },
26+
{ provide: MatDialogRef, useValue: mockDialogRef }
27+
]
28+
}).compileComponents();
29+
}));
30+
31+
beforeEach(() => {
32+
fixture = TestBed.createComponent(UnitCreateComponent);
33+
component = fixture.componentInstance;
34+
});
35+
36+
it('should create', () => {
37+
expect(component).toBeTruthy();
38+
});
39+
40+
describe('ngOnInit', () => {
41+
it('should call loadAllSimpleSites on initialization', () => {
42+
const mockSites: SiteDto[] = [
43+
{ siteId: 1, siteName: 'Site 1' } as SiteDto,
44+
{ siteId: 2, siteName: 'Site 2' } as SiteDto
45+
];
46+
const mockResult: OperationDataResult<Array<SiteDto>> = {
47+
success: true, message: '',
48+
model: mockSites
49+
};
50+
mockDeviceUserService.getDeviceUsersFiltered.and.returnValue(of(mockResult));
51+
52+
component.ngOnInit();
53+
54+
expect(mockDeviceUserService.getDeviceUsersFiltered).toHaveBeenCalled();
55+
});
56+
});
57+
58+
describe('loadAllSimpleSites', () => {
59+
it('should load and transform sites correctly', () => {
60+
const mockSites: SiteDto[] = [
61+
{ siteId: 1, siteName: 'Site 1', fullName: '' } as SiteDto,
62+
{ siteId: 2, siteName: 'Site 2', fullName: '' } as SiteDto
63+
];
64+
const mockResult: OperationDataResult<Array<SiteDto>> = {
65+
success: true, message: '',
66+
model: mockSites
67+
};
68+
mockDeviceUserService.getDeviceUsersFiltered.and.returnValue(of(mockResult));
69+
70+
component.loadAllSimpleSites();
71+
72+
expect(mockDeviceUserService.getDeviceUsersFiltered).toHaveBeenCalledWith(jasmine.any(DeviceUserRequestModel));
73+
expect(component.simpleSites.length).toBe(2);
74+
expect(component.simpleSites[0].fullName).toBe('Site 1');
75+
expect(component.simpleSites[1].fullName).toBe('Site 2');
76+
});
77+
78+
it('should handle empty sites response', () => {
79+
const mockResult: OperationDataResult<Array<SiteDto>> = {
80+
success: true, message: '',
81+
model: []
82+
};
83+
mockDeviceUserService.getDeviceUsersFiltered.and.returnValue(of(mockResult));
84+
85+
component.loadAllSimpleSites();
86+
87+
expect(component.simpleSites).toEqual([]);
88+
});
89+
});
90+
91+
describe('hide', () => {
92+
it('should close dialog with true when result is true', () => {
93+
component.hide(true);
94+
95+
expect(mockDialogRef.close).toHaveBeenCalledWith(true);
96+
});
97+
98+
it('should close dialog with false when result is false', () => {
99+
component.hide(false);
100+
101+
expect(mockDialogRef.close).toHaveBeenCalledWith(false);
102+
});
103+
104+
it('should close dialog with false by default', () => {
105+
component.hide();
106+
107+
expect(mockDialogRef.close).toHaveBeenCalledWith(false);
108+
});
109+
});
110+
111+
describe('createUnit', () => {
112+
it('should create unit successfully and close dialog', () => {
113+
const mockResult: OperationResult = {
114+
success: true,
115+
message: ''
116+
};
117+
mockUnitsService.createUnit.and.returnValue(of(mockResult));
118+
component.unitModel = new UnitModel();
119+
component.unitModel.siteId = 1;
120+
121+
component.createUnit();
122+
123+
expect(mockUnitsService.createUnit).toHaveBeenCalledWith(component.unitModel);
124+
expect(mockDialogRef.close).toHaveBeenCalledWith(true);
125+
});
126+
127+
it('should not close dialog when creation fails', () => {
128+
const mockResult: OperationResult = {
129+
success: false,
130+
message: ''
131+
};
132+
mockUnitsService.createUnit.and.returnValue(of(mockResult));
133+
component.unitModel = new UnitModel();
134+
135+
component.createUnit();
136+
137+
expect(mockUnitsService.createUnit).toHaveBeenCalled();
138+
expect(mockDialogRef.close).not.toHaveBeenCalled();
139+
});
140+
141+
it('should handle null response', () => {
142+
mockUnitsService.createUnit.and.returnValue(of(null));
143+
component.unitModel = new UnitModel();
144+
145+
component.createUnit();
146+
147+
expect(mockUnitsService.createUnit).toHaveBeenCalled();
148+
expect(mockDialogRef.close).not.toHaveBeenCalled();
149+
});
150+
});
151+
});
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
2+
import { UnitsOtpCodeComponent } from './units-otp-code.component';
3+
import { UnitsService } from 'src/app/common/services';
4+
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
5+
import { of } from 'rxjs';
6+
import { UnitDto, OperationDataResult } from 'src/app/common/models';
7+
8+
describe('UnitsOtpCodeComponent', () => {
9+
let component: UnitsOtpCodeComponent;
10+
let fixture: ComponentFixture<UnitsOtpCodeComponent>;
11+
let mockUnitsService: jasmine.SpyObj<UnitsService>;
12+
let mockDialogRef: jasmine.SpyObj<MatDialogRef<UnitsOtpCodeComponent>>;
13+
let mockDialogData: UnitDto;
14+
15+
beforeEach(waitForAsync(() => {
16+
mockUnitsService = jasmine.createSpyObj('UnitsService', ['requestOtp']);
17+
mockDialogRef = jasmine.createSpyObj('MatDialogRef', ['close']);
18+
mockDialogData = { id: 1, microtingUid: 12345, siteName: 'Test Site' } as UnitDto;
19+
20+
TestBed.configureTestingModule({
21+
declarations: [UnitsOtpCodeComponent],
22+
providers: [
23+
{ provide: UnitsService, useValue: mockUnitsService },
24+
{ provide: MatDialogRef, useValue: mockDialogRef },
25+
{ provide: MAT_DIALOG_DATA, useValue: mockDialogData }
26+
]
27+
}).compileComponents();
28+
}));
29+
30+
beforeEach(() => {
31+
fixture = TestBed.createComponent(UnitsOtpCodeComponent);
32+
component = fixture.componentInstance;
33+
fixture.detectChanges();
34+
});
35+
36+
it('should create', () => {
37+
expect(component).toBeTruthy();
38+
});
39+
40+
it('should initialize with dialog data', () => {
41+
expect(component.selectedUnitModel).toBeDefined();
42+
expect(component.selectedUnitModel.id).toBe(1);
43+
expect(component.selectedUnitModel.microtingUid).toBe(12345);
44+
});
45+
46+
describe('ngOnInit', () => {
47+
it('should initialize without errors', () => {
48+
expect(() => component.ngOnInit()).not.toThrow();
49+
});
50+
});
51+
52+
describe('hide', () => {
53+
it('should close dialog with true when result is true', () => {
54+
component.hide(true);
55+
56+
expect(mockDialogRef.close).toHaveBeenCalledWith(true);
57+
});
58+
59+
it('should close dialog with false when result is false', () => {
60+
component.hide(false);
61+
62+
expect(mockDialogRef.close).toHaveBeenCalledWith(false);
63+
});
64+
65+
it('should close dialog with false by default', () => {
66+
component.hide();
67+
68+
expect(mockDialogRef.close).toHaveBeenCalledWith(false);
69+
});
70+
});
71+
72+
describe('requestOtp', () => {
73+
it('should request OTP successfully and close dialog', () => {
74+
const mockUnit: UnitDto = { id: 1, microtingUid: 12345, otpCode: 6789 } as UnitDto;
75+
const mockResult: OperationDataResult<UnitDto> = {
76+
success: true, message: '',
77+
model: mockUnit
78+
};
79+
mockUnitsService.requestOtp.and.returnValue(of(mockResult));
80+
81+
component.requestOtp();
82+
83+
expect(mockUnitsService.requestOtp).toHaveBeenCalledWith(12345);
84+
expect(mockDialogRef.close).toHaveBeenCalledWith(true);
85+
});
86+
87+
it('should not close dialog when OTP request fails', () => {
88+
const mockResult: OperationDataResult<UnitDto> = {
89+
success: false, message: '',
90+
model: null
91+
};
92+
mockUnitsService.requestOtp.and.returnValue(of(mockResult));
93+
94+
component.requestOtp();
95+
96+
expect(mockUnitsService.requestOtp).toHaveBeenCalledWith(12345);
97+
expect(mockDialogRef.close).not.toHaveBeenCalled();
98+
});
99+
100+
it('should handle null response', () => {
101+
mockUnitsService.requestOtp.and.returnValue(of(null));
102+
103+
component.requestOtp();
104+
105+
expect(mockUnitsService.requestOtp).toHaveBeenCalled();
106+
expect(mockDialogRef.close).not.toHaveBeenCalled();
107+
});
108+
});
109+
});

0 commit comments

Comments
 (0)