docs: fix docs and associated code snippets for enabling more macro tasks in fakeAsync() (#35778)
				
					
				
			In the `testing` guide, there is a section discussing configuring `fakeAsync()` to handle more macro tasks (e.g. `HTMLCanvasElement#toBlob()`). Previously, the corresponding code snippets (some of which were hard-coded in the guide) were incorrect/incomplete and the associated tests were broken. This was discovered while enabling docs examples unit tests in #34374. This commit fixes the code snippets and associated tests and ensures the examples used in the guide come from an example app (i.e. are not hard-coded). Note: The docs examples unit tests are currently not run on CI. This will be fixed in #34374. PR Close #35778
This commit is contained in:
		
							parent
							
								
									ef2721b903
								
							
						
					
					
						commit
						8eb4a9d395
					
				| @ -1,6 +1,21 @@ | ||||
| // #docplaster
 | ||||
| // #docregion without-toBlob-macrotask
 | ||||
| import { TestBed, async, tick, fakeAsync } from '@angular/core/testing'; | ||||
| import { CanvasComponent } from './canvas.component'; | ||||
| 
 | ||||
| describe('CanvasComponent', () => { | ||||
|   // #enddocregion without-toBlob-macrotask
 | ||||
|   // #docregion enable-toBlob-macrotask
 | ||||
|   beforeEach(() => { | ||||
|     window['__zone_symbol__FakeAsyncTestMacroTask'] = [ | ||||
|       { | ||||
|         source: 'HTMLCanvasElement.toBlob', | ||||
|         callbackArgs: [{ size: 200 }], | ||||
|       }, | ||||
|     ]; | ||||
|   }); | ||||
|   // #enddocregion enable-toBlob-macrotask
 | ||||
|   // #docregion without-toBlob-macrotask
 | ||||
|   beforeEach(async(() => { | ||||
|     TestBed.configureTestingModule({ | ||||
|       declarations: [ | ||||
| @ -8,20 +23,16 @@ describe('CanvasComponent', () => { | ||||
|       ], | ||||
|     }).compileComponents(); | ||||
|   })); | ||||
|   beforeEach(() => { | ||||
|     window['__zone_symbol__FakeAsyncTestMacroTask'] = [ | ||||
|       { | ||||
|         source: 'HTMLCanvasElement.toBlob', | ||||
|         callbackArgs: [{ size: 200 }] | ||||
|       } | ||||
|     ]; | ||||
|   }); | ||||
| 
 | ||||
|   it('should be able to generate blob data from canvas', fakeAsync(() => { | ||||
|     const fixture = TestBed.createComponent(CanvasComponent); | ||||
|     const canvasComp = fixture.debugElement.componentInstance; | ||||
| 
 | ||||
|     fixture.detectChanges(); | ||||
|     expect(canvasComp.blobSize).toBe(0); | ||||
| 
 | ||||
|     tick(); | ||||
|     const app = fixture.debugElement.componentInstance; | ||||
|     expect(app.blobSize).toBeGreaterThan(0); | ||||
|     expect(canvasComp.blobSize).toBeGreaterThan(0); | ||||
|   })); | ||||
| }); | ||||
| 
 | ||||
| // #enddocregion without-toBlob-macrotask
 | ||||
|  | ||||
| @ -1,25 +1,32 @@ | ||||
| // #docplaster
 | ||||
| // #docregion import-canvas-patch
 | ||||
| // Import patch to make async `HTMLCanvasElement` methods (such as `.toBlob()`) Zone.js-aware.
 | ||||
| // Either import in `polyfills.ts` (if used in more than one places in the app) or in the component
 | ||||
| // file using `HTMLCanvasElement` (if it is only used in a single file).
 | ||||
| import 'zone.js/dist/zone-patch-canvas'; | ||||
| // #enddocregion import-canvas-patch
 | ||||
| // #docregion main
 | ||||
| import { Component, AfterViewInit, ViewChild, ElementRef } from '@angular/core'; | ||||
| 
 | ||||
| @Component({ | ||||
|   selector: 'sample-canvas', | ||||
|   template: '<canvas #sampleCanvas width="200" height="200"></canvas>' | ||||
|   template: '<canvas #sampleCanvas width="200" height="200"></canvas>', | ||||
| }) | ||||
| export class CanvasComponent implements AfterViewInit { | ||||
|   blobSize: number; | ||||
|   blobSize = 0; | ||||
|   @ViewChild('sampleCanvas') sampleCanvas: ElementRef; | ||||
| 
 | ||||
|   constructor() { } | ||||
| 
 | ||||
|   ngAfterViewInit() { | ||||
|     const canvas = this.sampleCanvas.nativeElement; | ||||
|     const canvas: HTMLCanvasElement = this.sampleCanvas.nativeElement; | ||||
|     const context = canvas.getContext('2d'); | ||||
|     if (context) { | ||||
| 
 | ||||
|     context.clearRect(0, 0, 200, 200); | ||||
|     context.fillStyle = '#FF1122'; | ||||
|     context.fillRect(0, 0, 200, 200); | ||||
|       canvas.toBlob((blob: any) => { | ||||
| 
 | ||||
|     canvas.toBlob(blob => { | ||||
|       this.blobSize = blob.size; | ||||
|     }); | ||||
|   } | ||||
| } | ||||
| } | ||||
| // #enddocregion main
 | ||||
|  | ||||
| @ -899,8 +899,7 @@ In production, change detection kicks in automatically | ||||
| when Angular creates a component or the user enters a keystroke or | ||||
| an asynchronous activity (e.g., AJAX) completes. | ||||
| 
 | ||||
| The `TestBed.createComponent` does _not_ trigger change detection. | ||||
| a fact confirmed in the revised test: | ||||
| The `TestBed.createComponent` does _not_ trigger change detection; a fact confirmed in the revised test: | ||||
| 
 | ||||
| <code-example | ||||
|   path="testing/src/app/banner/banner.component.spec.ts" region="test-w-o-detect-changes"></code-example> | ||||
| @ -1051,8 +1050,7 @@ attempt to reach an authentication server. | ||||
| These behaviors can be hard to intercept. | ||||
| It is far easier and safer to create and register a test double in place of the real `UserService`. | ||||
| 
 | ||||
| This particular test suite supplies a minimal mock of the `UserService` that satisfies the needs of the `WelcomeComponent` | ||||
| and its tests: | ||||
| This particular test suite supplies a minimal mock of the `UserService` that satisfies the needs of the `WelcomeComponent` and its tests: | ||||
| 
 | ||||
| <code-example | ||||
|   path="testing/src/app/welcome/welcome.component.spec.ts" | ||||
| @ -1266,8 +1264,7 @@ You do have to call [tick()](api/core/testing/tick) to advance the (virtual) clo | ||||
| Calling [tick()](api/core/testing/tick) simulates the passage of time until all pending asynchronous activities finish. | ||||
| In this case, it waits for the error handler's `setTimeout()`. | ||||
| 
 | ||||
| The [tick()](api/core/testing/tick) function accepts milliseconds and tickOptions as parameters, the millisecond (defaults to 0 if not provided) parameter represents how much the virtual clock advances. For example, if you have a `setTimeout(fn, 100)` in a `fakeAsync()` test, you need to use tick(100) to trigger the fn callback. The tickOptions is an optional parameter with a property called processNewMacroTasksSynchronously (defaults is true) represents whether to invoke | ||||
| new generated macro tasks when ticking. | ||||
| The [tick()](api/core/testing/tick) function accepts milliseconds and tickOptions as parameters, the millisecond (defaults to 0 if not provided) parameter represents how much the virtual clock advances. For example, if you have a `setTimeout(fn, 100)` in a `fakeAsync()` test, you need to use tick(100) to trigger the fn callback. The tickOptions is an optional parameter with a property called `processNewMacroTasksSynchronously` (defaults to true) represents whether to invoke new generated macro tasks when ticking. | ||||
| 
 | ||||
| <code-example | ||||
|   path="testing/src/app/demo/async-helper.spec.ts" | ||||
| @ -1331,51 +1328,46 @@ You can also use RxJS scheduler in `fakeAsync()` just like using `setTimeout()` | ||||
| 
 | ||||
| #### Support more macroTasks | ||||
| 
 | ||||
| By default `fakeAsync()` supports the following `macroTasks`. | ||||
| By default, `fakeAsync()` supports the following macro tasks. | ||||
| 
 | ||||
| - setTimeout | ||||
| - setInterval | ||||
| - requestAnimationFrame | ||||
| - webkitRequestAnimationFrame | ||||
| - mozRequestAnimationFrame | ||||
| - `setTimeout` | ||||
| - `setInterval` | ||||
| - `requestAnimationFrame` | ||||
| - `webkitRequestAnimationFrame` | ||||
| - `mozRequestAnimationFrame` | ||||
| 
 | ||||
| If you run other `macroTask` such as `HTMLCanvasElement.toBlob()`, `Unknown macroTask scheduled in fake async test` error will be thrown. | ||||
| If you run other macro tasks such as `HTMLCanvasElement.toBlob()`, an _"Unknown macroTask scheduled in fake async test"_ error will be thrown. | ||||
| 
 | ||||
| <code-tabs> | ||||
|   <code-pane | ||||
|     header="src/app/shared/canvas.component.spec.ts (failing)" | ||||
|     path="testing/src/app/shared/canvas.component.spec.ts" | ||||
|     header="src/app/shared/canvas.component.spec.ts"> | ||||
|     region="without-toBlob-macrotask"> | ||||
|   </code-pane> | ||||
|   <code-pane | ||||
|     header="src/app/shared/canvas.component.ts" | ||||
|     path="testing/src/app/shared/canvas.component.ts" | ||||
|     header="src/app/shared/canvas.component.ts"> | ||||
|     region="main"> | ||||
|   </code-pane> | ||||
| </code-tabs> | ||||
| 
 | ||||
| If you want to support such a case, you need to define the `macroTask` you want to support in `beforeEach()`. | ||||
| If you want to support such a case, you need to define the macro task you want to support in `beforeEach()`. | ||||
| For example: | ||||
| 
 | ||||
| ```javascript | ||||
| beforeEach(() => { | ||||
|   window['__zone_symbol__FakeAsyncTestMacroTask'] = [ | ||||
|     { | ||||
|       source: 'HTMLCanvasElement.toBlob', | ||||
|       callbackArgs: [{ size: 200 }] | ||||
|     } | ||||
|   ]; | ||||
| }); | ||||
| <code-example | ||||
|   header="src/app/shared/canvas.component.spec.ts (excerpt)" | ||||
|   path="testing/src/app/shared/canvas.component.spec.ts" | ||||
|   region="enable-toBlob-macrotask"> | ||||
| </code-example> | ||||
| 
 | ||||
| Note that in order to make the `<canvas>` element Zone.js-aware in your app, you need to import the `zone-patch-canvas` patch (either in `polyfills.ts` or in the specific file that uses `<canvas>`): | ||||
| 
 | ||||
| <code-example | ||||
|   header="src/polyfills.ts or src/app/shared/canvas.component.ts" | ||||
|   path="testing/src/app/shared/canvas.component.ts" | ||||
|   region="import-canvas-patch"> | ||||
| </code-example> | ||||
| 
 | ||||
| it('toBlob should be able to run in fakeAsync', fakeAsync(() => { | ||||
|     const canvas: HTMLCanvasElement = document.getElementById('canvas') as HTMLCanvasElement; | ||||
|     let blob = null; | ||||
|     canvas.toBlob(function(b) { | ||||
|       blob = b; | ||||
|     }); | ||||
|     tick(); | ||||
|     expect(blob.size).toBe(200); | ||||
|   }) | ||||
| ); | ||||
| ``` | ||||
| 
 | ||||
| #### Async observables | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user