angular 模板的固定装置没有使用信号(在测试中)进行更新,

ccrfmcuu  于 5个月前  发布在  Angular
关注(0)|答案(2)|浏览(58)

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

core

这是一个回归吗?

是的

描述

在以下测试场景中:

describe('Test with input', () => {
	@Component({
		standalone: true,
		template: `{{ htmlData }}`,
		changeDetection: ChangeDetectionStrategy.OnPush,
	})
	class TestComponentWithInput {
		data = input<string>()
		htmlData?: string
		constructor() {
			effect(() => {
				this.htmlData = this.data()
			})
		}
	}
	it('#1 should have "foobar" in template', () => {
		const fixture = TestBed.configureTestingModule({
			imports: [TestComponentWithInput],
		}).createComponent(TestComponentWithInput)
		fixture.detectChanges() // <---- This is necessary
		fixture.componentRef.setInput('data', 'foobar')
		fixture.detectChanges()

		expect(fixture.debugElement.nativeElement.textContent).toContain('foobar')
	})

	it('#2 should have "foobar" in template', () => {
		const fixture = TestBed.configureTestingModule({
			imports: [TestComponentWithInput],
		}).createComponent(TestComponentWithInput)
		//fixture.detectChanges() // <---- Template is not updated because of missing detectChanges
		fixture.componentRef.setInput('data', 'foobar')
		fixture.detectChanges()

		expect(fixture.debugElement.nativeElement.textContent).toContain('foobar')
	})
})

只有测试1起作用,测试2将失败。显然,在设置输入之前需要 fixture.detectChanges() 。否则,模板不会更新(请参见测试2)。
这是正确的行为还是一个bug?
如果这是预期的行为,我应该如何测试所需的信号输入,例如以下场景:

describe('Test with required input', () => {
	@Component({
		standalone: true,
		template: `{{ htmlData }}`,
		changeDetection: ChangeDetectionStrategy.OnPush,
	})
	class TestComponentWithRequiredInput {
		data = input.required<string>()
		htmlData?: string
		constructor() {
			effect(() => {
				this.htmlData = this.data()
			})
		}
	}
	it('#1 should have "foobar" in template', () => {
		const fixture = TestBed.configureTestingModule({
			imports: [TestComponentWithRequiredInput],
		}).createComponent(TestComponentWithRequiredInput)
		fixture.detectChanges() // <---- This is necessary but throws error
		fixture.componentRef.setInput('data', 'foobar')
		fixture.detectChanges()

		expect(fixture.debugElement.nativeElement.textContent).toContain('foobar')
	})

	it('#2 should have "foobar" in template (but i am broken)', () => {
		const fixture = TestBed.configureTestingModule({
			imports: [TestComponentWithRequiredInput],
		}).createComponent(TestComponentWithRequiredInput)
		//fixture.detectChanges() // <---- Template is not updated because of missing detectChanges
		fixture.componentRef.setInput('data', 'foobar')
		fixture.detectChanges()

		expect(fixture.debugElement.nativeElement.textContent).toContain('foobar')
	})
})

在这个场景中,两个测试都会失败。测试1失败(并抛出错误 NG0950: Input is required but no value is available yet )因为我需要在使用 fixture.detectChanges() 之前设置输入,而测试2失败是因为我在设置输入之前没有使用 fixture.detectChanges ,因此模板没有更新。
希望我能够描述我的困境 :)

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

  • 无响应*

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

  • 无响应*

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

Angular CLI: 18.0.4
Node: 20.12.2
Package Manager: npm 10.3.0
OS: darwin arm64

Angular: 18.0.3
... animations, cdk, common, compiler, compiler-cli, core, forms
... language-service, material, platform-browser
... platform-browser-dynamic, platform-server, router
... service-worker

Package                         Version
---------------------------------------------------------
@angular-devkit/architect       0.1703.8
@angular-devkit/build-angular   18.0.4
@angular-devkit/core            18.0.4
@angular-devkit/schematics      18.0.4
@angular/cli                    18.0.4
@angular/ssr                    18.0.4
@schematics/angular             18.0.4
ng-packagr                      18.0.0
rxjs                            7.8.1
typescript                      5.4.4
webpack                         5.92.0
zone.js                         0.14.2

还有其他信息吗?

  • 无响应*
4xrmg8kj

4xrmg8kj1#

你的单元测试实际上突出显示了团队正在寻求解决的效果调度问题。(参见 #56501 )
效果应该可能在模板更新之前运行。
目前,组件中的效果在检测到更改后更新模板。
这就是为什么它需要2次调用detectChanges。
这里有一个复现示例:https://stackblitz.com/edit/ng-jasmine-tghqjg?file=src%2Fapp%2Fapp.component.spec.ts

jm81lzqq

jm81lzqq2#

感谢您的澄清!

相关问题