Skip to content

Commit 1e3823a

Browse files
committed
test(schematics): add v49 migration tests
1 parent 95dce70 commit 1e3823a

21 files changed

+789
-0
lines changed

projects/element-ng/schematics/migrations/element-migration/element-migration.spec.ts

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,3 +131,91 @@ describe('to legacy migration', () => {
131131
await checkTemplateMigration(['module-based.accordion-inline-template.ts']);
132132
});
133133
});
134+
135+
describe('v48 to v49 migration', () => {
136+
let runner: SchematicTestRunner;
137+
let appTree: Tree;
138+
const name = 'migrate-v48-to-v49';
139+
const migrationCollectionPath = buildRelativeFromFile('../../migration.json');
140+
141+
beforeEach(async () => {
142+
runner = new SchematicTestRunner(name, migrationCollectionPath);
143+
appTree = await createTestApp(runner, { style: 'scss' });
144+
});
145+
146+
const checkTemplateMigration = async (
147+
fileNames: string[],
148+
basePath = `/projects/app/src/components/test/`
149+
): Promise<void> => {
150+
addTestFiles(
151+
appTree,
152+
Object.fromEntries(
153+
fileNames.map(fileName => [
154+
path.join(basePath, fileName),
155+
readFileSync(buildRelativeFromFile(path.join('files', fileName)), 'utf8')
156+
])
157+
)
158+
);
159+
160+
addTestFiles(appTree, {
161+
'/package.json': `{
162+
"dependencies": {
163+
"@siemens/element-ng": "48.0.0",
164+
"@siemens/maps-ng": "48.0.0",
165+
"@siemens/dashboards-ng": "48.0.0",
166+
"@siemens/charts-ng": "48.0.0"
167+
}
168+
}`
169+
});
170+
171+
const tree = await runner.runSchematic('migration-v49', { path: 'projects/app/src' }, appTree);
172+
for (const fileName of fileNames) {
173+
const expected = readFileSync(
174+
buildRelativeFromFile(path.join('files', 'expected.' + fileName)),
175+
'utf8'
176+
);
177+
const actual = tree.readContent(path.join(basePath, fileName));
178+
expect(actual).toEqual(expected);
179+
}
180+
};
181+
182+
it('should migrate ToastStateName to StatusType', async () => {
183+
await checkTemplateMigration(['toast-state-name.ts']);
184+
});
185+
186+
it('should migrate filtered search readonly attribute in inline templates', async () => {
187+
await checkTemplateMigration(['filtered-search-inline-readonly.ts']);
188+
});
189+
190+
it('should migrate Criterion types to CriterionValue and CriterionDefinition', async () => {
191+
await checkTemplateMigration(['filtered-search-criterion-types.ts']);
192+
});
193+
194+
it('should migrate select dropdownClose output in inline templates', async () => {
195+
await checkTemplateMigration(['select-dropdown-inline.ts']);
196+
});
197+
198+
it('should migrate unauthorized page component in inline templates', async () => {
199+
await checkTemplateMigration(['unauthorized-page-inline.ts']);
200+
});
201+
202+
it('should migrate CONFIG_TOKEN to SI_DASHBOARD_CONFIGURATION in inline usage', async () => {
203+
await checkTemplateMigration(['dashboard-config-inline.ts']);
204+
});
205+
206+
it('should migrate modal initialState to inputValues', async () => {
207+
await checkTemplateMigration(['modal-initial-state.ts']);
208+
});
209+
210+
it('should remove onResize method calls and output from si-map', async () => {
211+
await checkTemplateMigration(['map-onresize.ts']);
212+
});
213+
214+
it('should split numberOfDecimals into minNumberOfDecimals and maxNumberOfDecimals', async () => {
215+
await checkTemplateMigration(['chart-gauge-decimals.ts']);
216+
});
217+
218+
it('should migrate resize observer properties to signal calls', async () => {
219+
await checkTemplateMigration(['resize-observer.ts']);
220+
});
221+
});
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { Component } from '@angular/core';
2+
import { SiChartGaugeComponent } from '@siemens/charts-ng/gauge';
3+
4+
@Component({
5+
selector: 'app-dashboard',
6+
standalone: true,
7+
template: `
8+
<si-chart-gauge
9+
[value]="75"
10+
[numberOfDecimals]="2"
11+
[min]="0"
12+
[max]="100"
13+
></si-chart-gauge>
14+
15+
<si-chart-gauge [numberOfDecimals]="0"></si-chart-gauge>
16+
17+
<si-chart-gauge
18+
[value]="gaugeValue"
19+
[numberOfDecimals]="decimals"
20+
></si-chart-gauge>
21+
`,
22+
imports: [SiChartGaugeComponent]
23+
})
24+
export class DashboardComponent {
25+
gaugeValue = 85;
26+
decimals = 1;
27+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { Component, inject } from '@angular/core';
2+
import { CONFIG_TOKEN } from '@siemens/dashboards-ng';
3+
4+
@Component({
5+
selector: 'app-dashboard',
6+
standalone: true,
7+
template: `<div>Dashboard</div>`
8+
})
9+
export class DashboardComponent {
10+
private config = inject(CONFIG_TOKEN);
11+
12+
loadConfig() {
13+
const token = CONFIG_TOKEN;
14+
return { provide: CONFIG_TOKEN, useValue: this.config };
15+
}
16+
}
17+
18+
// Inline provider
19+
export const DASHBOARD_PROVIDERS = [
20+
{ provide: CONFIG_TOKEN, useValue: { mode: 'production' } }
21+
];
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { Component } from '@angular/core';
2+
import { SiChartGaugeComponent } from '@siemens/charts-ng/gauge';
3+
4+
@Component({
5+
selector: 'app-dashboard',
6+
standalone: true,
7+
template: `
8+
<si-chart-gauge
9+
[value]="75"
10+
[minNumberOfDecimals]="2" [maxNumberOfDecimals]="2"
11+
[min]="0"
12+
[max]="100"
13+
></si-chart-gauge>
14+
15+
<si-chart-gauge [minNumberOfDecimals]="0" [maxNumberOfDecimals]="0"></si-chart-gauge>
16+
17+
<si-chart-gauge
18+
[value]="gaugeValue"
19+
[minNumberOfDecimals]="decimals" [maxNumberOfDecimals]="decimals"
20+
></si-chart-gauge>
21+
`,
22+
imports: [SiChartGaugeComponent]
23+
})
24+
export class DashboardComponent {
25+
gaugeValue = 85;
26+
decimals = 1;
27+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { Component, inject } from '@angular/core';
2+
import { SI_DASHBOARD_CONFIGURATION } from '@siemens/dashboards-ng';
3+
4+
@Component({
5+
selector: 'app-dashboard',
6+
standalone: true,
7+
template: `<div>Dashboard</div>`
8+
})
9+
export class DashboardComponent {
10+
private config = inject(SI_DASHBOARD_CONFIGURATION);
11+
12+
loadConfig() {
13+
const token = SI_DASHBOARD_CONFIGURATION;
14+
return { provide: SI_DASHBOARD_CONFIGURATION, useValue: this.config };
15+
}
16+
}
17+
18+
// Inline provider
19+
export const DASHBOARD_PROVIDERS = [
20+
{ provide: SI_DASHBOARD_CONFIGURATION, useValue: { mode: 'production' } }
21+
];
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/**
2+
* Copyright (c) Siemens 2016 - 2025
3+
* SPDX-License-Identifier: MIT
4+
*/
5+
import { Component, input } from '@angular/core';
6+
import { Observable } from 'rxjs';
7+
import {
8+
CriterionValue,
9+
CriterionDefinition,
10+
SearchCriteria,
11+
SiFilteredSearchModule
12+
} from '@siemens/element-ng/filtered-search';
13+
14+
@Component({
15+
selector: 'app-criterion-types-test',
16+
template: `
17+
<si-filtered-search
18+
[criteria]="criteria()"
19+
[lazyCriterionProvider]="lazyCriterionProvider()"
20+
(search)="onSearch($event)">
21+
</si-filtered-search>
22+
`,
23+
imports: [SiFilteredSearchModule],
24+
standalone: true
25+
})
26+
export class CriterionTypesTestComponent {
27+
// Test input with CriterionDefinition[]
28+
criteria = input<CriterionDefinition[]>([]);
29+
30+
// Test input with function returning Observable<CriterionDefinition[]>
31+
lazyCriterionProvider = input<
32+
(typed: string, searchCriteria?: SearchCriteria) => Observable<CriterionDefinition[]>
33+
>();
34+
35+
// Test method parameter and variable declaration
36+
onSearch(searchCriteria: SearchCriteria): void {
37+
const criterionValues: CriterionValue[] = searchCriteria.criteria;
38+
console.log(criterionValues);
39+
}
40+
41+
// Test method return type
42+
getCriteria(): CriterionDefinition[] {
43+
return [];
44+
}
45+
46+
// Test with arrays
47+
processCriteria(items: CriterionValue[]): void {
48+
const filtered: CriterionValue[] = items.filter(c => c.id !== '');
49+
}
50+
51+
// Test in generic type
52+
handleData(data: Array<CriterionValue>): CriterionValue[] {
53+
return data;
54+
}
55+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/**
2+
* Copyright (c) Siemens 2016 - 2025
3+
* SPDX-License-Identifier: MIT
4+
*/
5+
import { Component } from '@angular/core';
6+
import { SiFilteredSearchModule } from '@siemens/element-ng/filtered-search';
7+
8+
@Component({
9+
selector: 'app-inline-readonly-test',
10+
template: `
11+
<div>
12+
<si-filtered-search [disabled]="true"></si-filtered-search>
13+
<si-filtered-search [disabled]="editMode === false" [criteria]="criteria"></si-filtered-search>
14+
<si-filtered-search
15+
[disabled]="isDisabled"
16+
[placeholder]="'Enter search criteria'"
17+
(search)="onSearch($event)">
18+
</si-filtered-search>
19+
</div>
20+
`,
21+
imports: [SiFilteredSearchModule],
22+
standalone: true
23+
})
24+
export class InlineReadonlyTestComponent {
25+
editMode = false;
26+
isDisabled = true;
27+
criteria = [];
28+
29+
onSearch(event: any): void {
30+
console.log(event);
31+
}
32+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { Component, ViewChild } from '@angular/core';
2+
import { SiMapComponent } from '@siemens/maps-ng';
3+
4+
@Component({
5+
selector: 'app-map',
6+
standalone: true,
7+
template: `
8+
<si-map
9+
#map
10+
[center]="center"
11+
[zoom]="12"
12+
13+
>
14+
</si-map>
15+
<button (click)="triggerResize()">Resize</button>
16+
`
17+
})
18+
export class MapComponent {
19+
@ViewChild('map') mapComponent!: SiMapComponent;
20+
center = { lat: 40.7128, lng: -74.0060 };
21+
22+
triggerResize() {
23+
// This method call should be removed as it has no effect
24+
this.mapComponent.onResize();
25+
}
26+
27+
handleResize() {
28+
console.log('Map resized');
29+
}
30+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { Component } from '@angular/core';
2+
import { SiModalService } from '@siemens/element-ng/modal';
3+
import { MyModalComponent } from './my-modal.component';
4+
5+
@Component({
6+
selector: 'app-test',
7+
standalone: true,
8+
template: `<button (click)="openModal()">Open</button>`
9+
})
10+
export class TestComponent {
11+
constructor(private modalService: SiModalService) {}
12+
13+
openModal() {
14+
this.modalService.show(MyModalComponent, {
15+
inputValues: { title: 'Hello', data: { id: 1 } }
16+
});
17+
}
18+
19+
openModalWithOptions() {
20+
const modalRef = this.modalService.show(MyModalComponent, {
21+
inputValues: {
22+
title: 'Edit Item',
23+
item: { name: 'Test', value: 100 }
24+
},
25+
keyboard: false
26+
});
27+
return modalRef;
28+
}
29+
30+
openModalInline() {
31+
return this.modalService.show(MyModalComponent, { inputValues: { mode: 'create' } });
32+
}
33+
34+
openModalMultiline() {
35+
this.modalService.show(MyModalComponent, {
36+
inputValues: {
37+
user: { name: 'John', email: 'john@example.com' },
38+
permissions: ['read', 'write'],
39+
config: { theme: 'dark' }
40+
}
41+
});
42+
}
43+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { Component } from '@angular/core';
2+
import { SiResponsiveContainerDirective } from '@siemens/element-ng/resize-observer';
3+
4+
@Component({
5+
selector: 'app-test',
6+
template: '<div></div>'
7+
})
8+
export class TestComponent {
9+
checkSize(directive: SiResponsiveContainerDirective): void {
10+
// Property access patterns
11+
if (directive.xs()) {
12+
console.log('Extra small');
13+
}
14+
15+
const small = directive.sm();
16+
const medium = directive.md();
17+
18+
// In expressions
19+
const result = directive.lg() ? 'large' : 'not large';
20+
21+
// Chained access
22+
const xl = this.getDirective().xl();
23+
24+
// Multiple on same line
25+
if (directive.xs() || directive.sm() || directive.md()) {
26+
console.log('Small to medium');
27+
}
28+
29+
// In template literal
30+
const msg = `Size is ${directive.xxl() ? 'XXL' : 'smaller'}`;
31+
32+
// In logical expressions
33+
const responsive = directive.sm() && directive.md();
34+
}
35+
36+
getDirective(): SiResponsiveContainerDirective {
37+
return null as any;
38+
}
39+
}

0 commit comments

Comments
 (0)