ng g @angular/core:standalone应该正确迁移测试组件,

soat7uwm  于 10个月前  发布在  Angular
关注(0)|答案(4)|浏览(92)

哪个@angular/*包是bug的来源?

core

这是个回归吗?

描述

  1. ng new standalone-migration --defaults
  2. cd standalone-migration
  3. ng update @angular/core@next @angular/cli@next --force
  4. ng g c hello

使用以下内容更新 HelloComponent 的测试:

  1. import { Component } from '@angular/core';
  2. import { TestBed } from '@angular/core/testing';
  3. import { HelloComponent } from './hello.component';
  4. @Component({
  5. template: '<app-hello></app-hello>'
  6. })
  7. class TestComponent { }
  8. describe('HelloComponent', () => {
  9. beforeEach(() => TestBed.configureTestingModule({
  10. declarations: [TestComponent, HelloComponent]
  11. }));
  12. it('should display hello', () => {
  13. const fixture = TestBed.createComponent(TestComponent);
  14. expect(fixture.nativeElement.querySelector('p').textContent).toContain('hello works!');
  15. });
  16. });

然后使用 ng g @angular/core:standalone --defaults 运行迁移。
它将迁移到:

  1. import { Component } from '@angular/core';
  2. import { TestBed } from '@angular/core/testing';
  3. import { HelloComponent } from './hello.component';
  4. @Component({
  5. template: '<app-hello></app-hello>',
  6. standalone: true
  7. })
  8. class TestComponent { }
  9. describe('HelloComponent', () => {
  10. beforeEach(() => TestBed.configureTestingModule({
  11. imports: [TestComponent, HelloComponent]
  12. }));
  13. it('should display hello', () => {
  14. const fixture = TestBed.createComponent(TestComponent);
  15. expect(fixture.nativeElement.querySelector('p').textContent).toContain('hello works!');
  16. });
  17. });

请注意,TestComponent 现在是独立的,但它不导入 HelloComponent
因此会抛出:

  1. Chrome 110.0.0.0 (Mac OS 10.15.7) HelloComponent should display hello FAILED
  2. Error: NG0304: 'app-hello' is not a known element (used in the 'TestComponent' component template):

这可以通过将 imports: [HelloComponent] 添加到 TestComponent 来修复。
另外,请注意,在理想情况下,configureTestingModule 可以简化为:

  1. beforeEach(() => TestBed.configureTestingModule({
  2. imports: [TestComponent] // no need for HelloComponent
  3. }));

请提供一个最小复现bug的链接

  • 无响应*

请提供您看到的异常或错误

  • 无响应*

请提供您发现此bug的环境(运行 ng version )

  1. Angular CLI: 15.2.0-next.3
  2. Node: 16.17.0
  3. Package Manager: npm 8.19.3
  4. OS: darwin arm64
  5. Angular: 15.2.0-next.4
  6. ... animations, common, compiler, compiler-cli, core, forms
  7. ... platform-browser, platform-browser-dynamic, router
  8. Package Version
  9. ---------------------------------------------------------
  10. @angular-devkit/architect 0.1502.0-next.3
  11. @angular-devkit/build-angular 15.2.0-next.3
  12. @angular-devkit/core 15.2.0-next.3
  13. @angular-devkit/schematics 15.2.0-next.3
  14. @angular/cli 15.2.0-next.3
  15. @schematics/angular 15.2.0-next.3
  16. rxjs 7.8.0
  17. typescript 4.9.5

还有其他要说的吗?

  • 无响应*
db2dz4w8

db2dz4w81#

很遗憾,我们对此无能为力。我们使用Angular编译器来确定要添加到imports数组的内容,而编译器不会分析测试模块。迁移尝试通过将测试模块的imports数组中的任何内容添加到组件中来处理这个问题,但这并不总是正确的。

2w3rbyxf

2w3rbyxf2#

感谢@crisbeto的回答。

当将HelloComponent添加到测试模块的imports中时,是否也可以将其添加到TestComponent的imports中?

aij0ehis

aij0ehis3#

它没有被添加,因为在TestComponent被使用的各个测试中,可能加载了具有相同选择器的不同的组件。通常,迁移的目标不是让一切都100%正确,而是让你大部分达到目标,并可能需要一些手动修复。

mctunoxg

mctunoxg4#

对于未来的读者:我制作了一个脚本,将所有的 TestHostComponents 还原为正常组件。这对其他人可能有用:

  1. import { Project, SyntaxKind } from 'ts-morph';
  2. const prettier = require('prettier');
  3. const path = require('path');
  4. console.info('💡 start TestHostComponent standalone demigratie');
  5. const project = new Project();
  6. project.addSourceFilesAtPaths('**/*.spec.ts');
  7. project.getSourceFiles().forEach((sourceFile) => {
  8. const classesInSpec = sourceFile.getChildrenOfKind(SyntaxKind.ClassDeclaration);
  9. const testHostComponents = classesInSpec.filter((c) => c.getName() === 'TestHostComponent');
  10. if (testHostComponents.length === 0) {
  11. return;
  12. }
  13. console.info('converting ' + sourceFile.getBaseName());
  14. // remove imports and standalone from TestHostComponent Component decorator
  15. testHostComponents
  16. .flatMap((c) => c.getDecorators())
  17. .map((d) => d.getArguments()[0])
  18. .map((a) => (<any>a).getProperties())
  19. .forEach((a) => {
  20. a.filter((x: any) => x.getName() === 'standalone' || x.getName() === 'imports').forEach((x: any) => x.remove());
  21. });
  22. // remove TestHostComponent from imports array
  23. const calls = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression);
  24. calls
  25. .filter((c) => c.compilerNode.expression.getText() === 'TestBed.configureTestingModule')
  26. .map((o) => o.getArguments()[0])
  27. .map((a) => a.getChildrenOfKind(SyntaxKind.PropertyAssignment).filter((x) => x.getName() === 'imports')[0])
  28. .filter(Boolean)
  29. .flatMap((a) =>
  30. a
  31. .getChildrenOfKind(SyntaxKind.ArrayLiteralExpression)[0]
  32. .getChildrenOfKind(SyntaxKind.SyntaxList)[0]
  33. .getChildrenOfKind(SyntaxKind.Identifier)
  34. .filter((i) => i.getText() === 'TestHostComponent')
  35. )
  36. .forEach((x) => {
  37. const prevComma = x.getPreviousSiblingIfKind(SyntaxKind.CommaToken);
  38. const nextComma = x.getNextSiblingIfKind(SyntaxKind.CommaToken);
  39. prevComma ? prevComma.replaceWithText('') : nextComma?.replaceWithText('');
  40. x.replaceWithText('');
  41. });
  42. // add declarations array with TestHostCompont in it
  43. const tb = sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression);
  44. tb.filter((c) => c.compilerNode.expression.getText() === 'TestBed.configureTestingModule')
  45. .map((o) => o.getArguments()[0])
  46. .map((x) => x.getChildrenOfKind(SyntaxKind.SyntaxList)[0])
  47. .forEach((s) => {
  48. s.addChildText(', \n declarations: [TestHostComponent]');
  49. });
  50. const prettierOptions = prettier.resolveConfig.sync(path.resolve('.prettierrc'));
  51. console.info('formatting ' + sourceFile.getBaseName());
  52. const newS = prettier.format(sourceFile.getText(), { ...prettierOptions, parser: 'typescript' });
  53. sourceFile.replaceWithText(newS);
  54. console.info('✅ ' + sourceFile.getBaseName());
  55. });
  56. project.save();

你需要将 ts-morph 作为开发依赖项,然后使用 ts-node 运行文件 ts-node revert-test-hostcomponents.ts

展开查看全部

相关问题