Skip to content

Commit c162187

Browse files
committed
Add CI workflow and unit tests for frontend
Introduces a GitHub Actions workflow for frontend CI, including Node.js setup and test execution. Adds unit tests for AppComponent and PropertyFormComponent, and refactors PropertyFormComponent for improved type safety and immutability.
1 parent 5d3a520 commit c162187

File tree

4 files changed

+131
-11
lines changed

4 files changed

+131
-11
lines changed

.github/workflows/ci-frontend.yml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
name: CI Frontend
2+
3+
on:
4+
push:
5+
paths:
6+
- 'axiomatic-ui/**'
7+
- '.github/workflows/ci-frontend.yml'
8+
pull_request:
9+
paths:
10+
- 'axiomatic-ui/**'
11+
- '.github/workflows/ci-frontend.yml'
12+
13+
jobs:
14+
test:
15+
runs-on: ubuntu-latest
16+
17+
defaults:
18+
run:
19+
working-directory: axiomatic-ui
20+
21+
steps:
22+
- name: Checkout repository
23+
uses: actions/checkout@v4
24+
25+
- name: Use Node.js 20
26+
uses: actions/setup-node@v4
27+
with:
28+
node-version: '20'
29+
cache: 'npm'
30+
cache-dependency-path: |
31+
axiomatic-ui/package-lock.json
32+
33+
- name: Install dependencies
34+
run: npm ci
35+
36+
- name: Run unit tests
37+
run: npm test -- --watch=false --browsers=ChromeHeadless
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { TestBed } from '@angular/core/testing';
2+
import { RouterTestingModule } from '@angular/router/testing';
3+
import { AppComponent } from './app.component';
4+
5+
describe('AppComponent', () => {
6+
beforeEach(async () => {
7+
await TestBed.configureTestingModule({
8+
imports: [RouterTestingModule, AppComponent],
9+
}).compileComponents();
10+
});
11+
12+
it('should create the app', () => {
13+
const fixture = TestBed.createComponent(AppComponent);
14+
const app = fixture.componentInstance;
15+
expect(app).toBeTruthy();
16+
});
17+
18+
it('should render navbar and router outlet', () => {
19+
const fixture = TestBed.createComponent(AppComponent);
20+
fixture.detectChanges();
21+
const compiled = fixture.nativeElement as HTMLElement;
22+
23+
expect(compiled.querySelector('app-navbar')).not.toBeNull();
24+
expect(compiled.querySelector('router-outlet')).not.toBeNull();
25+
});
26+
});

axiomatic-ui/src/app/components/property-form/property-form.component.ts

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,26 +23,27 @@ export class PropertyFormComponent {
2323
@Input() value: PropertyRequest = {} as PropertyRequest;
2424
@Input() disabled = false;
2525
@Input() loading = false;
26-
@Output() valueChange = new EventEmitter<PropertyRequest>();
27-
28-
showAdvanced = false;
2926

27+
@Output() valueChange = new EventEmitter<PropertyRequest>();
3028
/** submit verso il parent (Dashboard) */
3129
@Output() submit = new EventEmitter<PropertyRequest>();
3230

33-
onSubmit() {
34-
// Se vuoi fare normalizzazione qui, fallo prima dell’emit
31+
showAdvanced = false;
32+
33+
onSubmit(): void {
3534
this.submit.emit(this.value);
3635
}
3736

38-
onChange() {
39-
// emetto una copia per evitare mutazioni in-place
40-
this.valueChange.emit({ ...(this.value || {}) });
37+
onChange(): void {
38+
const nextValue: PropertyRequest = {
39+
...(this.value || ({} as PropertyRequest)),
40+
};
41+
this.valueChange.emit(nextValue);
4142
}
4243

43-
toggleAdvanced() {
44+
toggleAdvanced(): void {
4445
this.showAdvanced = !this.showAdvanced;
4546
}
4647

47-
energyClasses = ['A', 'B', 'C', 'D', 'E', 'F', 'G'];
48-
}
48+
readonly energyClasses = ['A', 'B', 'C', 'D', 'E', 'F', 'G'];
49+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { ComponentFixture, TestBed } from '@angular/core/testing';
2+
import { PropertyFormComponent } from './property-form.component';
3+
import { PropertyRequest } from '../../models/property';
4+
5+
describe('PropertyFormComponent', () => {
6+
let component: PropertyFormComponent;
7+
let fixture: ComponentFixture<PropertyFormComponent>;
8+
9+
beforeEach(async () => {
10+
await TestBed.configureTestingModule({
11+
imports: [PropertyFormComponent],
12+
}).compileComponents();
13+
14+
fixture = TestBed.createComponent(PropertyFormComponent);
15+
component = fixture.componentInstance;
16+
});
17+
18+
it('should create', () => {
19+
expect(component).toBeTruthy();
20+
});
21+
22+
it('should emit submit with current value', () => {
23+
const value = { location: 'Milan' } as PropertyRequest;
24+
component.value = value;
25+
26+
const spy = spyOn(component.submit, 'emit');
27+
component.onSubmit();
28+
29+
expect(spy).toHaveBeenCalledWith(value);
30+
});
31+
32+
it('should emit valueChange on change with a shallow copy', () => {
33+
const value = { location: 'Rome', size_sqm: 80 } as PropertyRequest;
34+
component.value = value;
35+
36+
let emitted: PropertyRequest | undefined;
37+
component.valueChange.subscribe(v => (emitted = v));
38+
39+
component.onChange();
40+
41+
expect(emitted).toBeDefined();
42+
expect(emitted).toEqual(value);
43+
// deve essere un nuovo riferimento
44+
expect(emitted).not.toBe(value);
45+
});
46+
47+
it('should toggle advanced section flag', () => {
48+
expect(component.showAdvanced).toBeFalse();
49+
50+
component.toggleAdvanced();
51+
expect(component.showAdvanced).toBeTrue();
52+
53+
component.toggleAdvanced();
54+
expect(component.showAdvanced).toBeFalse();
55+
});
56+
});

0 commit comments

Comments
 (0)