5 lines
29 KiB
JSON
5 lines
29 KiB
JSON
{
|
|
"id": "guide/testing-components-basics",
|
|
"title": "Basics of testing components",
|
|
"contents": "\n\n\n<div class=\"github-links\">\n <a href=\"https://github.com/angular/angular/edit/master/aio/content/guide/testing-components-basics.md?message=docs%3A%20describe%20your%20change...\" aria-label=\"Suggest Edits\" title=\"Suggest Edits\"><i class=\"material-icons\" aria-hidden=\"true\" role=\"img\">mode_edit</i></a>\n</div>\n\n\n<div class=\"content\">\n <h1 id=\"basics-of-testing-components\">Basics of testing components<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/testing-components-basics#basics-of-testing-components\"><i class=\"material-icons\">link</i></a></h1>\n<p>A component, unlike all other parts of an Angular application,\ncombines an HTML template and a TypeScript class.\nThe component truly is the template and the class <em>working together</em>. To adequately test a component, you should test that they work together\nas intended.</p>\n<p>Such tests require creating the component's host element in the browser DOM,\nas Angular does, and investigating the component class's interaction with\nthe DOM as described by its template.</p>\n<p>The Angular <code><a href=\"api/core/testing/TestBed\" class=\"code-anchor\">TestBed</a></code> facilitates this kind of testing as you'll see in the sections below.\nBut in many cases, <em>testing the component class alone</em>, without DOM involvement,\ncan validate much of the component's behavior in an easier, more obvious way.</p>\n<div class=\"alert is-helpful\">\n<p> For the sample app that the testing guides describe, see the <live-example name=\"testing\" embedded-style=\"\" nodownload=\"\">sample app</live-example>.</p>\n<p> For the tests features in the testing guides, see <live-example name=\"testing\" stackblitz=\"specs\" nodownload=\"\">tests</live-example>.</p>\n</div>\n<a id=\"component-class-testing\"></a>\n<h2 id=\"component-class-testing\">Component class testing<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/testing-components-basics#component-class-testing\"><i class=\"material-icons\">link</i></a></h2>\n<p>Test a component class on its own as you would test a service class.</p>\n<p>Component class testing should be kept very clean and simple.\nIt should test only a single unit.\nAt first glance, you should be able to understand\nwhat the test is testing.</p>\n<p>Consider this <code>LightswitchComponent</code> which toggles a light on and off\n(represented by an on-screen message) when the user clicks the button.</p>\n<code-example path=\"testing/src/app/demo/demo.ts\" region=\"LightswitchComp\" header=\"app/demo/demo.ts (LightswitchComp)\">\n@<a href=\"api/core/Component\" class=\"code-anchor\">Component</a>({\n selector: 'lightswitch-comp',\n template: `\n <button (click)=\"clicked()\">Click me!</button>\n <span>{{message}}</span>`\n})\nexport class LightswitchComponent {\n isOn = false;\n clicked() { this.isOn = !this.isOn; }\n get message() { return `The light is ${this.isOn ? 'On' : 'Off'}`; }\n}\n\n</code-example>\n<p>You might decide only to test that the <code>clicked()</code> method\ntoggles the light's <em>on/off</em> state and sets the message appropriately.</p>\n<p>This component class has no dependencies. To test these types of classes, follow the same steps as you would for a service that has no dependencies:</p>\n<ol>\n<li>Create a component using the new keyword.</li>\n<li>Poke at its API.</li>\n<li>Assert expectations on its public state.</li>\n</ol>\n<code-example path=\"testing/src/app/demo/demo.spec.ts\" region=\"Lightswitch\" header=\"app/demo/demo.spec.ts (Lightswitch tests)\">\ndescribe('LightswitchComp', () => {\n it('#clicked() should toggle #isOn', () => {\n const comp = new LightswitchComponent();\n expect(comp.isOn).toBe(false, 'off at first');\n comp.clicked();\n expect(comp.isOn).toBe(true, 'on after click');\n comp.clicked();\n expect(comp.isOn).toBe(false, 'off after second click');\n });\n\n it('#clicked() should set #message to \"is on\"', () => {\n const comp = new LightswitchComponent();\n expect(comp.message).toMatch(/is off/i, 'off at first');\n comp.clicked();\n expect(comp.message).toMatch(/is on/i, 'on after clicked');\n });\n});\n\n</code-example>\n<p>Here is the <code>DashboardHeroComponent</code> from the <em>Tour of Heroes</em> tutorial.</p>\n<code-example path=\"testing/src/app/dashboard/dashboard-hero.component.ts\" region=\"class\" header=\"app/dashboard/dashboard-hero.component.ts (component)\">\nexport class DashboardHeroComponent {\n @<a href=\"api/core/Input\" class=\"code-anchor\">Input</a>() hero: Hero;\n @<a href=\"api/core/Output\" class=\"code-anchor\">Output</a>() selected = new <a href=\"api/core/EventEmitter\" class=\"code-anchor\">EventEmitter</a><Hero>();\n click() { this.selected.emit(this.hero); }\n}\n\n</code-example>\n<p>It appears within the template of a parent component,\nwhich binds a <em>hero</em> to the <code>@<a href=\"api/core/Input\" class=\"code-anchor\">Input</a></code> property and\nlistens for an event raised through the <em>selected</em> <code>@<a href=\"api/core/Output\" class=\"code-anchor\">Output</a></code> property.</p>\n<p>You can test that the class code works without creating the <code>DashboardHeroComponent</code>\nor its parent component.</p>\n<code-example path=\"testing/src/app/dashboard/dashboard-hero.component.spec.ts\" region=\"class-only\" header=\"app/dashboard/dashboard-hero.component.spec.ts (class tests)\">\nit('raises the selected event when clicked', () => {\n const comp = new DashboardHeroComponent();\n const hero: Hero = {id: 42, name: 'Test'};\n comp.hero = hero;\n\n comp.selected.subscribe((selectedHero: Hero) => expect(selectedHero).toBe(hero));\n comp.click();\n});\n\n</code-example>\n<p>When a component has dependencies, you may wish to use the <code><a href=\"api/core/testing/TestBed\" class=\"code-anchor\">TestBed</a></code> to both\ncreate the component and its dependencies.</p>\n<p>The following <code>WelcomeComponent</code> depends on the <code>UserService</code> to know the name of the user to greet.</p>\n<code-example path=\"testing/src/app/welcome/welcome.component.ts\" region=\"class\" header=\"app/welcome/welcome.component.ts\">\nexport class WelcomeComponent implements <a href=\"api/core/OnInit\" class=\"code-anchor\">OnInit</a> {\n welcome: string;\n constructor(private userService: UserService) { }\n\n ngOnInit(): void {\n this.welcome = this.userService.isLoggedIn ?\n 'Welcome, ' + this.userService.user.name : 'Please log in.';\n }\n}\n\n</code-example>\n<p>You might start by creating a mock of the <code>UserService</code> that meets the minimum needs of this component.</p>\n<code-example path=\"testing/src/app/welcome/welcome.component.spec.ts\" region=\"mock-user-service\" header=\"app/welcome/welcome.component.spec.ts (MockUserService)\">\nclass MockUserService {\n isLoggedIn = true;\n user = { name: 'Test User'};\n}\n\n</code-example>\n<p>Then provide and inject <em>both the</em> <strong>component</strong> <em>and the service</em> in the <code><a href=\"api/core/testing/TestBed\" class=\"code-anchor\">TestBed</a></code> configuration.</p>\n<code-example path=\"testing/src/app/welcome/welcome.component.spec.ts\" region=\"class-only-before-each\" header=\"app/welcome/welcome.component.spec.ts (class-only setup)\">\nbeforeEach(() => {\n TestBed.configureTestingModule({\n // provide the component-under-test and dependent service\n providers: [\n WelcomeComponent,\n { provide: UserService, useClass: MockUserService }\n ]\n });\n // inject both the component and the dependent service.\n comp = TestBed.inject(WelcomeComponent);\n userService = TestBed.inject(UserService);\n});\n\n</code-example>\n<p>Then exercise the component class, remembering to call the <a href=\"guide/lifecycle-hooks\">lifecycle hook methods</a> as Angular does when running the app.</p>\n<code-example path=\"testing/src/app/welcome/welcome.component.spec.ts\" region=\"class-only-tests\" header=\"app/welcome/welcome.component.spec.ts (class-only tests)\">\nit('should not have welcome message after construction', () => {\n expect(comp.welcome).toBeUndefined();\n});\n\nit('should welcome logged in user after Angular calls ngOnInit', () => {\n comp.ngOnInit();\n expect(comp.welcome).toContain(userService.user.name);\n});\n\nit('should ask user to log in if not logged in after ngOnInit', () => {\n userService.isLoggedIn = false;\n comp.ngOnInit();\n expect(comp.welcome).not.toContain(userService.user.name);\n expect(comp.welcome).toContain('log in');\n});\n\n</code-example>\n<h2 id=\"component-dom-testing\">Component DOM testing<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/testing-components-basics#component-dom-testing\"><i class=\"material-icons\">link</i></a></h2>\n<p>Testing the component <em>class</em> is as easy as <a href=\"guide/testing-services\">testing a service</a>.</p>\n<p>But a component is more than just its class.\nA component interacts with the DOM and with other components.\nThe <em>class-only</em> tests can tell you about class behavior.\nThey cannot tell you if the component is going to render properly,\nrespond to user input and gestures, or integrate with its parent and child components.</p>\n<p>None of the <em>class-only</em> tests above can answer key questions about how the\ncomponents actually behave on screen.</p>\n<ul>\n<li>Is <code>Lightswitch.clicked()</code> bound to anything such that the user can invoke it?</li>\n<li>Is the <code>Lightswitch.message</code> displayed?</li>\n<li>Can the user actually select the hero displayed by <code>DashboardHeroComponent</code>?</li>\n<li>Is the hero name displayed as expected (i.e, in uppercase)?</li>\n<li>Is the welcome message displayed by the template of <code>WelcomeComponent</code>?</li>\n</ul>\n<p>These may not be troubling questions for the simple components illustrated above.\nBut many components have complex interactions with the DOM elements\ndescribed in their templates, causing HTML to appear and disappear as\nthe component state changes.</p>\n<p>To answer these kinds of questions, you have to create the DOM elements associated\nwith the components, you must examine the DOM to confirm that component state\ndisplays properly at the appropriate times, and you must simulate user interaction\nwith the screen to determine whether those interactions cause the component to\nbehave as expected.</p>\n<p>To write these kinds of test, you'll use additional features of the <code><a href=\"api/core/testing/TestBed\" class=\"code-anchor\">TestBed</a></code>\nas well as other testing helpers.</p>\n<h3 id=\"cli-generated-tests\">CLI-generated tests<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/testing-components-basics#cli-generated-tests\"><i class=\"material-icons\">link</i></a></h3>\n<p>The CLI creates an initial test file for you by default when you ask it to\ngenerate a new component.</p>\n<p>For example, the following CLI command generates a <code>BannerComponent</code> in the <code>app/banner</code> folder (with inline template and styles):</p>\n<code-example language=\"sh\" class=\"code-shell\">\nng generate component banner --inline-template --inline-style --module app\n</code-example>\n<p>It also generates an initial test file for the component, <code>banner-external.component.spec.ts</code>, that looks like this:</p>\n<code-example path=\"testing/src/app/banner/banner-initial.component.spec.ts\" region=\"v1\" header=\"app/banner/banner-external.component.spec.ts (initial)\">\nimport { <a href=\"api/core/testing/ComponentFixture\" class=\"code-anchor\">ComponentFixture</a>, <a href=\"api/core/testing/TestBed\" class=\"code-anchor\">TestBed</a>, <a href=\"api/core/testing/waitForAsync\" class=\"code-anchor\">waitForAsync</a> } from '@angular/core/testing';\n\nimport { BannerComponent } from './banner.component';\n\ndescribe('BannerComponent', () => {\n let component: BannerComponent;\n let fixture: <a href=\"api/core/testing/ComponentFixture\" class=\"code-anchor\">ComponentFixture</a><BannerComponent>;\n\n beforeEach(<a href=\"api/core/testing/waitForAsync\" class=\"code-anchor\">waitForAsync</a>(() => {\n TestBed.configureTestingModule({declarations: [BannerComponent]}).compileComponents();\n }));\n\n beforeEach(() => {\n fixture = TestBed.createComponent(BannerComponent);\n component = fixture.componentInstance;\n fixture.detectChanges();\n });\n\n it('should create', () => {\n expect(component).toBeDefined();\n });\n});\n\n</code-example>\n<div class=\"alert is-helpful\">\n<p>Because <code>compileComponents</code> is asynchronous, it uses\nthe <a href=\"api/core/testing/waitForAsync\"><code>waitForAsync</code></a> utility\nfunction imported from <code>@angular/core/testing</code>.</p>\n<p>Please refer to the <a href=\"guide/testing-components-scenarios#waitForAsync\">waitForAsync</a> section for more details.</p>\n</div>\n<h3 id=\"reduce-the-setup\">Reduce the setup<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/testing-components-basics#reduce-the-setup\"><i class=\"material-icons\">link</i></a></h3>\n<p>Only the last three lines of this file actually test the component\nand all they do is assert that Angular can create the component.</p>\n<p>The rest of the file is boilerplate setup code anticipating more advanced tests that <em>might</em> become necessary if the component evolves into something substantial.</p>\n<p>You'll learn about these advanced test features below.\nFor now, you can radically reduce this test file to a more manageable size:</p>\n<code-example path=\"testing/src/app/banner/banner-initial.component.spec.ts\" region=\"v2\" header=\"app/banner/banner-initial.component.spec.ts (minimal)\">\ndescribe('BannerComponent (minimal)', () => {\n it('should create', () => {\n TestBed.configureTestingModule({declarations: [BannerComponent]});\n const fixture = TestBed.createComponent(BannerComponent);\n const component = fixture.componentInstance;\n expect(component).toBeDefined();\n });\n});\n\n</code-example>\n<p>In this example, the metadata object passed to <code>TestBed.configureTestingModule</code>\nsimply declares <code>BannerComponent</code>, the component to test.</p>\n<code-example path=\"testing/src/app/banner/banner-initial.component.spec.ts\" region=\"configureTestingModule\">\nTestBed.configureTestingModule({declarations: [BannerComponent]});\n\n</code-example>\n<div class=\"alert is-helpful\">\n<p>There's no need to declare or import anything else.\nThe default test module is pre-configured with\nsomething like the <code><a href=\"api/platform-browser/BrowserModule\" class=\"code-anchor\">BrowserModule</a></code> from <code>@angular/platform-browser</code>.</p>\n<p>Later you'll call <code>TestBed.configureTestingModule()</code> with\nimports, providers, and more declarations to suit your testing needs.\nOptional <code>override</code> methods can further fine-tune aspects of the configuration.</p>\n</div>\n<a id=\"create-component\"></a>\n<h3 id=\"createcomponent\"><em>createComponent()</em><a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/testing-components-basics#createcomponent\"><i class=\"material-icons\">link</i></a></h3>\n<p>After configuring <code><a href=\"api/core/testing/TestBed\" class=\"code-anchor\">TestBed</a></code>, you call its <code>createComponent()</code> method.</p>\n<code-example path=\"testing/src/app/banner/banner-initial.component.spec.ts\" region=\"createComponent\">\nconst fixture = TestBed.createComponent(BannerComponent);\n\n</code-example>\n<p><code>TestBed.createComponent()</code> creates an instance of the <code>BannerComponent</code>,\nadds a corresponding element to the test-runner DOM,\nand returns a <a href=\"guide/testing-components-basics#component-fixture\"><code>ComponentFixture</code></a>.</p>\n<div class=\"alert is-important\">\n<p>Do not re-configure <code><a href=\"api/core/testing/TestBed\" class=\"code-anchor\">TestBed</a></code> after calling <code>createComponent</code>.</p>\n<p>The <code>createComponent</code> method freezes the current <code><a href=\"api/core/testing/TestBed\" class=\"code-anchor\">TestBed</a></code> definition,\nclosing it to further configuration.</p>\n<p>You cannot call any more <code><a href=\"api/core/testing/TestBed\" class=\"code-anchor\">TestBed</a></code> configuration methods, not <code>configureTestingModule()</code>,\nnor <code>get()</code>, nor any of the <code>override...</code> methods.\nIf you try, <code><a href=\"api/core/testing/TestBed\" class=\"code-anchor\">TestBed</a></code> throws an error.</p>\n</div>\n<a id=\"component-fixture\"></a>\n<h3 id=\"componentfixture\"><em>ComponentFixture</em><a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/testing-components-basics#componentfixture\"><i class=\"material-icons\">link</i></a></h3>\n<p>The <a href=\"api/core/testing/ComponentFixture\">ComponentFixture</a> is a test harness for interacting with the created component and its corresponding element.</p>\n<p>Access the component instance through the fixture and confirm it exists with a Jasmine expectation:</p>\n<code-example path=\"testing/src/app/banner/banner-initial.component.spec.ts\" region=\"componentInstance\">\nconst component = fixture.componentInstance;\nexpect(component).toBeDefined();\n\n</code-example>\n<h3 id=\"beforeeach\"><em>beforeEach()</em><a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/testing-components-basics#beforeeach\"><i class=\"material-icons\">link</i></a></h3>\n<p>You will add more tests as this component evolves.\nRather than duplicate the <code><a href=\"api/core/testing/TestBed\" class=\"code-anchor\">TestBed</a></code> configuration for each test,\nyou refactor to pull the setup into a Jasmine <code>beforeEach()</code> and some supporting variables:</p>\n<code-example path=\"testing/src/app/banner/banner-initial.component.spec.ts\" region=\"v3\">\ndescribe('BannerComponent (with beforeEach)', () => {\n let component: BannerComponent;\n let fixture: <a href=\"api/core/testing/ComponentFixture\" class=\"code-anchor\">ComponentFixture</a><BannerComponent>;\n\n beforeEach(() => {\n TestBed.configureTestingModule({declarations: [BannerComponent]});\n fixture = TestBed.createComponent(BannerComponent);\n component = fixture.componentInstance;\n });\n\n it('should create', () => {\n expect(component).toBeDefined();\n });\n});\n\n</code-example>\n<p>Now add a test that gets the component's element from <code>fixture.nativeElement</code> and\nlooks for the expected text.</p>\n<code-example path=\"testing/src/app/banner/banner-initial.component.spec.ts\" region=\"v4-test-2\">\nit('should contain \"banner works!\"', () => {\n const bannerElement: HTMLElement = fixture.nativeElement;\n expect(bannerElement.textContent).toContain('banner works!');\n});\n\n</code-example>\n<a id=\"native-element\"></a>\n<h3 id=\"nativeelement\"><em>nativeElement</em><a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/testing-components-basics#nativeelement\"><i class=\"material-icons\">link</i></a></h3>\n<p>The value of <code><a href=\"api/core/testing/ComponentFixture#nativeElement\" class=\"code-anchor\">ComponentFixture.nativeElement</a></code> has the <code>any</code> type.\nLater you'll encounter the <code><a href=\"api/core/DebugElement#nativeElement\" class=\"code-anchor\">DebugElement.nativeElement</a></code> and it too has the <code>any</code> type.</p>\n<p>Angular can't know at compile time what kind of HTML element the <code>nativeElement</code> is or\nif it even is an HTML element.\nThe app might be running on a <em>non-browser platform</em>, such as the server or a\n<a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API\">Web Worker</a>,\nwhere the element may have a diminished API or not exist at all.</p>\n<p>The tests in this guide are designed to run in a browser so a\n<code>nativeElement</code> value will always be an <code>HTMLElement</code> or\none of its derived classes.</p>\n<p>Knowing that it is an <code>HTMLElement</code> of some sort, you can use\nthe standard HTML <code>querySelector</code> to dive deeper into the element tree.</p>\n<p>Here's another test that calls <code>HTMLElement.querySelector</code> to get the paragraph element and look for the banner text:</p>\n<code-example path=\"testing/src/app/banner/banner-initial.component.spec.ts\" region=\"v4-test-3\">\nit('should have <p> with \"banner works!\"', () => {\n const bannerElement: HTMLElement = fixture.nativeElement;\n const p = bannerElement.querySelector('p');\n expect(p.textContent).toEqual('banner works!');\n});\n\n</code-example>\n<a id=\"debug-element\"></a>\n<h3 id=\"debugelement\"><em>DebugElement</em><a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/testing-components-basics#debugelement\"><i class=\"material-icons\">link</i></a></h3>\n<p>The Angular <em>fixture</em> provides the component's element directly through the <code>fixture.nativeElement</code>.</p>\n<code-example path=\"testing/src/app/banner/banner-initial.component.spec.ts\" region=\"nativeElement\">\nconst bannerElement: HTMLElement = fixture.nativeElement;\n\n</code-example>\n<p>This is actually a convenience method, implemented as <code>fixture.debugElement.nativeElement</code>.</p>\n<code-example path=\"testing/src/app/banner/banner-initial.component.spec.ts\" region=\"debugElement-nativeElement\">\nconst bannerDe: <a href=\"api/core/DebugElement\" class=\"code-anchor\">DebugElement</a> = fixture.debugElement;\nconst bannerEl: HTMLElement = bannerDe.nativeElement;\n\n</code-example>\n<p>There's a good reason for this circuitous path to the element.</p>\n<p>The properties of the <code>nativeElement</code> depend upon the runtime environment.\nYou could be running these tests on a <em>non-browser</em> platform that doesn't have a DOM or\nwhose DOM-emulation doesn't support the full <code>HTMLElement</code> API.</p>\n<p>Angular relies on the <code><a href=\"api/core/DebugElement\" class=\"code-anchor\">DebugElement</a></code> abstraction to work safely across <em>all supported platforms</em>.\nInstead of creating an HTML element tree, Angular creates a <code><a href=\"api/core/DebugElement\" class=\"code-anchor\">DebugElement</a></code> tree that wraps the <em>native elements</em> for the runtime platform.\nThe <code>nativeElement</code> property unwraps the <code><a href=\"api/core/DebugElement\" class=\"code-anchor\">DebugElement</a></code> and returns the platform-specific element object.</p>\n<p>Because the sample tests for this guide are designed to run only in a browser,\na <code>nativeElement</code> in these tests is always an <code>HTMLElement</code>\nwhose familiar methods and properties you can explore within a test.</p>\n<p>Here's the previous test, re-implemented with <code>fixture.debugElement.nativeElement</code>:</p>\n<code-example path=\"testing/src/app/banner/banner-initial.component.spec.ts\" region=\"v4-test-4\">\nit('should find the <p> with fixture.debugElement.nativeElement)', () => {\n const bannerDe: <a href=\"api/core/DebugElement\" class=\"code-anchor\">DebugElement</a> = fixture.debugElement;\n const bannerEl: HTMLElement = bannerDe.nativeElement;\n const p = bannerEl.querySelector('p');\n expect(p.textContent).toEqual('banner works!');\n});\n\n</code-example>\n<p>The <code><a href=\"api/core/DebugElement\" class=\"code-anchor\">DebugElement</a></code> has other methods and properties that\nare useful in tests, as you'll see elsewhere in this guide.</p>\n<p>You import the <code><a href=\"api/core/DebugElement\" class=\"code-anchor\">DebugElement</a></code> symbol from the Angular core library.</p>\n<code-example path=\"testing/src/app/banner/banner-initial.component.spec.ts\" region=\"import-debug-element\">\nimport { <a href=\"api/core/DebugElement\" class=\"code-anchor\">DebugElement</a> } from '@angular/core';\n\n</code-example>\n<a id=\"by-css\"></a>\n<h3 id=\"bycss\"><em>By.css()</em><a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/testing-components-basics#bycss\"><i class=\"material-icons\">link</i></a></h3>\n<p>Although the tests in this guide all run in the browser,\nsome apps might run on a different platform at least some of the time.</p>\n<p>For example, the component might render first on the server as part of a strategy to make the application launch faster on poorly connected devices. The server-side renderer might not support the full HTML element API.\nIf it doesn't support <code>querySelector</code>, the previous test could fail.</p>\n<p>The <code><a href=\"api/core/DebugElement\" class=\"code-anchor\">DebugElement</a></code> offers query methods that work for all supported platforms.\nThese query methods take a <em>predicate</em> function that returns <code>true</code> when a node in the <code><a href=\"api/core/DebugElement\" class=\"code-anchor\">DebugElement</a></code> tree matches the selection criteria.</p>\n<p>You create a <em>predicate</em> with the help of a <code><a href=\"api/platform-browser/By\" class=\"code-anchor\">By</a></code> class imported from a\nlibrary for the runtime platform. Here's the <code><a href=\"api/platform-browser/By\" class=\"code-anchor\">By</a></code> import for the browser platform:</p>\n<code-example path=\"testing/src/app/banner/banner-initial.component.spec.ts\" region=\"import-by\">\nimport { <a href=\"api/platform-browser/By\" class=\"code-anchor\">By</a> } from '@angular/platform-browser';\n\n</code-example>\n<p>The following example re-implements the previous test with\n<code>DebugElement.query()</code> and the browser's <code>By.css</code> method.</p>\n<code-example path=\"testing/src/app/banner/banner-initial.component.spec.ts\" region=\"v4-test-5\">\nit('should find the <p> with fixture.debugElement.query(By.css)', () => {\n const bannerDe: <a href=\"api/core/DebugElement\" class=\"code-anchor\">DebugElement</a> = fixture.debugElement;\n const paragraphDe = bannerDe.query(By.css('p'));\n const p: HTMLElement = paragraphDe.nativeElement;\n expect(p.textContent).toEqual('banner works!');\n});\n\n</code-example>\n<p>Some noteworthy observations:</p>\n<ul>\n<li>The <code><a href=\"api/platform-browser/By#css\" class=\"code-anchor\">By.css()</a></code> static method selects <code><a href=\"api/core/DebugElement\" class=\"code-anchor\">DebugElement</a></code> nodes\nwith a <a href=\"https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Getting_started/Selectors\" title=\"CSS selectors\">standard CSS selector</a>.</li>\n<li>The query returns a <code><a href=\"api/core/DebugElement\" class=\"code-anchor\">DebugElement</a></code> for the paragraph.</li>\n<li>You must unwrap that result to get the paragraph element.</li>\n</ul>\n<p>When you're filtering by CSS selector and only testing properties of a browser's <em>native element</em>, the <code>By.css</code> approach may be overkill.</p>\n<p>It's often easier and more clear to filter with a standard <code>HTMLElement</code> method\nsuch as <code>querySelector()</code> or <code>querySelectorAll()</code>.</p>\n\n \n</div>\n\n<!-- links to this doc:\n - guide/testing\n - guide/testing-components-scenarios\n-->\n<!-- links from this doc:\n - api/core/Component\n - api/core/DebugElement\n - api/core/DebugElement#nativeElement\n - api/core/EventEmitter\n - api/core/Input\n - api/core/OnInit\n - api/core/Output\n - api/core/testing/ComponentFixture\n - api/core/testing/ComponentFixture#nativeElement\n - api/core/testing/TestBed\n - api/core/testing/waitForAsync\n - api/platform-browser/BrowserModule\n - api/platform-browser/By\n - api/platform-browser/By#css\n - guide/lifecycle-hooks\n - guide/testing-components-basics#basics-of-testing-components\n - guide/testing-components-basics#beforeeach\n - guide/testing-components-basics#bycss\n - guide/testing-components-basics#cli-generated-tests\n - guide/testing-components-basics#component-class-testing\n - guide/testing-components-basics#component-dom-testing\n - guide/testing-components-basics#component-fixture\n - guide/testing-components-basics#componentfixture\n - guide/testing-components-basics#createcomponent\n - guide/testing-components-basics#debugelement\n - guide/testing-components-basics#nativeelement\n - guide/testing-components-basics#reduce-the-setup\n - guide/testing-components-scenarios#waitForAsync\n - guide/testing-services\n - https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API\n - https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Getting_started/Selectors\n - https://github.com/angular/angular/edit/master/aio/content/guide/testing-components-basics.md?message=docs%3A%20describe%20your%20change...\n-->"
|
|
} |