Skip to content

Commit 71771a9

Browse files
committed
add coverage for create.component
1 parent c5078c5 commit 71771a9

1 file changed

Lines changed: 134 additions & 17 deletions

File tree

libs/shared/base-editor-components/src/create/create.component.spec.ts

Lines changed: 134 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
22
import { provideZonelessChangeDetection } from '@angular/core';
33
import { provideNoopAnimations } from '@angular/platform-browser/animations';
44
import { FormsModule } from '@angular/forms';
5-
import { BrowserModule, By } from '@angular/platform-browser';
5+
import { BrowserModule } from '@angular/platform-browser';
66
import { of, throwError } from 'rxjs';
77
import { TranslateModule } from '@ngx-translate/core';
88
import { MockHandlerService } from '@keira/shared/base-abstract-classes';
@@ -13,9 +13,35 @@ import { anything, instance, mock, reset, when } from 'ts-mockito';
1313

1414
import { CreateComponent } from './create.component';
1515

16+
class CreateComponentPage extends PageObject<CreateComponent<TableRow>> {
17+
constructor(fixture: ComponentFixture<CreateComponent<TableRow>>) {
18+
super(fixture);
19+
}
20+
21+
get idInput(): HTMLInputElement {
22+
return this.query<HTMLInputElement>('#id');
23+
}
24+
get selectBtn(): HTMLInputElement {
25+
return this.query<HTMLInputElement>('#select-button');
26+
}
27+
get idFreeStatusBox(): HTMLDivElement {
28+
return this.query<HTMLDivElement>('#id-free-status');
29+
}
30+
get sourceInput(): HTMLInputElement {
31+
return this.getInputById('source-id');
32+
}
33+
get copyInput(): HTMLInputElement {
34+
return this.getInputById('method-copy');
35+
}
36+
get copyRadio(): HTMLInputElement | null {
37+
return this.query<HTMLInputElement>('#method-copy', false);
38+
}
39+
}
40+
1641
describe('CreateComponent', () => {
1742
let component: CreateComponent<any>;
1843
let fixture: ComponentFixture<CreateComponent<any>>;
44+
let page: CreateComponentPage;
1945

2046
const fakeQueryService: any = {
2147
getMaxId: () => of([{ max: 5 }]),
@@ -29,6 +55,7 @@ describe('CreateComponent', () => {
2955
beforeEach(async () => {
3056
await TestBed.configureTestingModule({
3157
imports: [FormsModule, TranslateModule.forRoot(), CreateComponent],
58+
providers: [provideZonelessChangeDetection(), provideNoopAnimations()],
3259
}).compileComponents();
3360

3461
fixture = TestBed.createComponent(CreateComponent);
@@ -40,23 +67,23 @@ describe('CreateComponent', () => {
4067
component.queryService = fakeQueryService;
4168
component.handlerService = fakeHandlerService;
4269
fixture.detectChanges();
70+
page = new CreateComponentPage(fixture);
4371
});
4472

4573
it('does not render the copy option when allowCopy is false', () => {
4674
// Default allowCopy is false
4775
fixture.detectChanges();
48-
const copyRadio = fixture.debugElement.query(By.css('#method-copy'));
76+
const copyRadio = page.copyRadio;
4977
expect(copyRadio).toBeNull();
5078
expect(component.creationMethod).toBe('blank');
5179
});
5280

5381
it('renders the copy option when allowCopy is true', () => {
5482
component.allowCopy = true;
5583
fixture.detectChanges();
56-
const copyRadio = fixture.debugElement.query(By.css('#method-copy'));
57-
expect(copyRadio).not.toBeNull();
84+
const copyInput = page.copyInput;
85+
expect(copyInput).toBeDefined();
5886
// when allowed the copy radio should not be disabled
59-
const copyInput = copyRadio.nativeElement as HTMLInputElement;
6087
expect(copyInput.disabled).toBeFalse();
6188
});
6289

@@ -76,18 +103,6 @@ describe('CreateComponent', () => {
76103
});
77104
// (Additional tests below use the imports declared above)
78105

79-
class CreateComponentPage extends PageObject<CreateComponent<TableRow>> {
80-
get idInput(): HTMLInputElement {
81-
return this.query<HTMLInputElement>('#id');
82-
}
83-
get selectBtn(): HTMLInputElement {
84-
return this.query<HTMLInputElement>('#select-button');
85-
}
86-
get idFreeStatusBox(): HTMLDivElement {
87-
return this.query<HTMLDivElement>('#id-free-status');
88-
}
89-
}
90-
91106
describe('CreateComponent', () => {
92107
const mockTable = 'mock_table';
93108
const mockId = 'mockId';
@@ -192,4 +207,106 @@ describe('CreateComponent', () => {
192207
component.customStartingId = 10;
193208
expect(component['calculateNextId'](5)).toEqual(10);
194209
});
210+
211+
it('validates source id and calls select with copy params on create', async () => {
212+
const { fixture, page, component } = setup();
213+
214+
// Enable copying and switch to copy method directly (radio may not always be present in this env)
215+
component.allowCopy = true;
216+
component.creationMethod = 'copy';
217+
fixture.detectChanges();
218+
await fixture.whenStable();
219+
220+
const sourceRadio = page.copyRadio;
221+
// Guard: the radio is optional in this test runner, but the source input must be present for copy flow
222+
if (sourceRadio) {
223+
(sourceRadio as HTMLInputElement).checked = true;
224+
sourceRadio.dispatchEvent(new Event('change'));
225+
fixture.detectChanges();
226+
}
227+
228+
// Provide an existing source id and trigger input (setup returns an existing item for `takenId`)
229+
const sourceInput = page.sourceInput;
230+
page.setInputValue(sourceInput, takenId);
231+
fixture.detectChanges();
232+
await fixture.whenStable();
233+
234+
expect(component.isSourceIdValid).toBeTrue();
235+
236+
// Prepare a new id and create
237+
component.idModel = 2000;
238+
component.isIdFree = true;
239+
fixture.detectChanges();
240+
241+
const selectSpy = spyOn(component.handlerService, 'select');
242+
243+
page.clickElement(page.selectBtn);
244+
245+
expect(selectSpy).toHaveBeenCalledTimes(1);
246+
expect(selectSpy).toHaveBeenCalledWith(true, 2000, undefined, true, `${takenId}`);
247+
});
248+
249+
it('does not allow a higher source value than max value', () => {
250+
const { component } = setup();
251+
component.sourceIdModel = MAX_INT_UNSIGNED_VALUE + 1;
252+
253+
(component as any).checkMaxValue();
254+
255+
expect(component.sourceIdModel).toEqual(MAX_INT_UNSIGNED_VALUE);
256+
});
257+
258+
it('onCreationMethodChange clears source state when switched to blank', () => {
259+
const { component } = setup();
260+
component.creationMethod = 'copy';
261+
component.sourceIdModel = 123;
262+
component.isSourceIdValid = true;
263+
264+
component.creationMethod = 'blank';
265+
(component as any).onCreationMethodChange();
266+
267+
expect(component.sourceIdModel).toBeUndefined();
268+
expect(component.isSourceIdValid).toBeFalse();
269+
});
270+
271+
it('checkSourceId handles errors and marks source invalid', () => {
272+
const { component, MockedMysqlQueryService } = setup();
273+
reset(MockedMysqlQueryService);
274+
when(MockedMysqlQueryService.selectAll(mockTable, mockId, anything())).thenReturn(throwError('error'));
275+
276+
component.sourceIdModel = 999;
277+
(component as any).checkSourceId();
278+
279+
expect(component.isSourceIdValid).toBeFalse();
280+
expect(component.loading).toBe(false);
281+
});
282+
283+
it('checkSourceId early-return when no sourceIdModel', () => {
284+
const { component } = setup();
285+
component.sourceIdModel = undefined;
286+
287+
(component as any).checkSourceId();
288+
289+
expect(component.isSourceIdValid).toBeFalse();
290+
});
291+
292+
it('isFormValid correctly evaluates copy vs blank methods', () => {
293+
const { component } = setup();
294+
295+
// blank creation method
296+
component.creationMethod = 'blank';
297+
component.idModel = 1;
298+
component.isIdFree = true;
299+
expect((component as any).isFormValid()).toBeTrue();
300+
301+
// copy method without source data should be invalid
302+
component.creationMethod = 'copy';
303+
component.sourceIdModel = undefined;
304+
component.isSourceIdValid = false;
305+
expect((component as any).isFormValid()).toBeFalse();
306+
307+
// copy method with valid source should be valid
308+
component.sourceIdModel = 123;
309+
component.isSourceIdValid = true;
310+
expect((component as any).isFormValid()).toBeTrue();
311+
});
195312
});

0 commit comments

Comments
 (0)