fix(migrations): incorrect stats when migrating queries with best effort mode (#59463)

We previously did count forcibly ignored queries as incompatible. This
resulted in incorrect migration stats that are printed upon migration
completion.

See: #58657

PR Close #59463
This commit is contained in:
Paul Gschwendtner 2025-01-10 14:18:17 +00:00 committed by kirjs
parent 09a9fafc53
commit eb2fcd1896
3 changed files with 140 additions and 2 deletions

View file

@ -25,6 +25,7 @@ import {
ClassFieldDescriptor,
ClassIncompatibilityReason,
FieldIncompatibilityReason,
nonIgnorableFieldIncompatibilities,
} from '../signal-migration/src';
import {checkIncompatiblePatterns} from '../signal-migration/src/passes/problematic_patterns/common_incompatible_patterns';
import {migrateHostBindings} from '../signal-migration/src/passes/reference_migration/migrate_host_bindings';
@ -617,6 +618,15 @@ export class SignalQueriesMigration extends TsurgeComplexMigration<
continue;
}
// Do not count queries that were forcibly ignored via best effort mode.
if (
this.config.bestEffortMode &&
(info.fieldReason === null ||
!nonIgnorableFieldIncompatibilities.includes(info.fieldReason))
) {
continue;
}
incompatibleQueries++;
if (info.classReason !== null) {

View file

@ -24,7 +24,7 @@ describe('signal queries migration', () => {
host.sync.write(normalize(filePath), virtualFs.stringToFileBuffer(contents));
}
function runMigration(options?: {path?: string}) {
function runMigration(options?: {bestEffortMode?: boolean}) {
return runner.runSchematic('signal-queries-migration', options, tree);
}
@ -69,4 +69,68 @@ describe('signal queries migration', () => {
const content = tree.readContent('/index.ts').replace(/\s+/g, ' ');
expect(content).toContain("readonly ref = contentChild.required<ElementRef>('ref');");
});
it('should report correct statistics', async () => {
writeFile(`node_modules/@tsconfig/strictest/tsconfig.json`, `{}`);
writeFile(
`tsconfig.json`,
JSON.stringify({
extends: `@tsconfig/strictest/tsconfig.json`,
}),
);
writeFile(
'/index.ts',
`
import {ContentChild, ElementRef, Directive} from '@angular/core';
@Directive({})
export class SomeDirective {
@ContentChild('ref') ref!: ElementRef;
@ContentChild('ref') ref2: ElementRef|null = null;
someFn() {
this.ref2 = null;
}
}`,
);
const messages: string[] = [];
runner.logger.subscribe((m) => messages.push(m.message));
await runMigration();
expect(messages).toContain(` -> Migrated 1/2 queries.`);
});
it('should report correct statistics with best effort mode', async () => {
writeFile(`node_modules/@tsconfig/strictest/tsconfig.json`, `{}`);
writeFile(
`tsconfig.json`,
JSON.stringify({
extends: `@tsconfig/strictest/tsconfig.json`,
}),
);
writeFile(
'/index.ts',
`
import {ContentChild, ElementRef, Directive} from '@angular/core';
@Directive({})
export class SomeDirective {
@ContentChild('ref') ref!: ElementRef;
@ContentChild('ref') ref2: ElementRef|null = null;
someFn() {
this.ref2 = null;
}
}`,
);
const messages: string[] = [];
runner.logger.subscribe((m) => messages.push(m.message));
await runMigration({bestEffortMode: true});
expect(messages).toContain(` -> Migrated 2/2 queries.`);
});
});

View file

@ -24,7 +24,7 @@ describe('signal input migration', () => {
host.sync.write(normalize(filePath), virtualFs.stringToFileBuffer(contents));
}
function runMigration(options?: {path?: string}) {
function runMigration(options?: {bestEffortMode?: boolean}) {
return runner.runSchematic('signal-input-migration', options, tree);
}
@ -94,4 +94,68 @@ describe('signal input migration', () => {
const content = tree.readContent('/index.ts').replace(/\s+/g, ' ');
expect(content).toContain('readonly name = input.required<string>()');
});
it('should report correct statistics', async () => {
writeFile(`node_modules/@tsconfig/strictest/tsconfig.json`, `{}`);
writeFile(
`tsconfig.json`,
JSON.stringify({
extends: `@tsconfig/strictest/tsconfig.json`,
}),
);
writeFile(
'/index.ts',
`
import {Input, Directive} from '@angular/core';
@Directive({})
export class SomeDirective {
@Input({required: true}) name = '';
@Input({required: true}) lastName = '';
someFn() {
this.lastName = 'other name';
}
}`,
);
const messages: string[] = [];
runner.logger.subscribe((m) => messages.push(m.message));
await runMigration();
expect(messages).toContain(` -> Migrated 1/2 inputs.`);
});
it('should report correct statistics with best effort mode', async () => {
writeFile(`node_modules/@tsconfig/strictest/tsconfig.json`, `{}`);
writeFile(
`tsconfig.json`,
JSON.stringify({
extends: `@tsconfig/strictest/tsconfig.json`,
}),
);
writeFile(
'/index.ts',
`
import {Input, Directive} from '@angular/core';
@Directive({})
export class SomeDirective {
@Input({required: true}) name = '';
@Input({required: true}) lastName = '';
someFn() {
this.lastName = 'other name';
}
}`,
);
const messages: string[] = [];
runner.logger.subscribe((m) => messages.push(m.message));
await runMigration({bestEffortMode: true});
expect(messages).toContain(` -> Migrated 2/2 inputs.`);
});
});