Angular单元测试与E2E测试
本文介绍了Angular单元测试和E2E测试的配置与测试方法。示例APP使用Angular 7 CLI创建,已配置好基础测试环境,生成了测试样例代码。默认,Angular单元测试使用Jasmine测试框架和Karma测试运行器,E2E测试使用Jasmine测试框架和Protractor端到端测试框架。
配置单元测试Jasmine是一个用于测试JavaScript的行为驱动开发框架,不依赖于任何其他JavaScript框架。 配置文件单元测试配置文件test.ts和karma.conf.js: import ‘zone.js/dist/zone-testing‘; import { getTestBed } from ‘@angular/core/testing‘; import { BrowserDynamicTestingModule,platformBrowserDynamicTesting } from ‘@angular/platform-browser-dynamic/testing‘; declare const require: any; // First,initialize the Angular testing environment. getTestBed().initTestEnvironment( BrowserDynamicTestingModule,platformBrowserDynamicTesting() ); // Then we find all the tests. const context = require.context(‘./‘,true,/.spec.ts$/); // And load the modules. context.keys().map(context); 测试文件扩展名必须为.spec.ts。 module.exports = function (config) { config.set({ basePath: ‘‘,frameworks: [‘jasmine‘,‘@angular-devkit/build-angular‘],plugins: [ require(‘karma-jasmine‘),require(‘karma-chrome-launcher‘),require(‘karma-jasmine-html-reporter‘),require(‘karma-coverage-istanbul-reporter‘),require(‘@angular-devkit/build-angular/plugins/karma‘) ],client: { clearContext: false // leave Jasmine Spec Runner output visible in browser },coverageIstanbulReporter: { dir: require(‘path‘).join(__dirname,‘../coverage‘),reports: [‘html‘,‘lcovonly‘],fixWebpackSourcePaths: true },reporters: [‘progress‘,‘kjhtml‘],port: 9876,colors: true,logLevel: config.LOG_INFO,autoWatch: true,browsers: [‘Chrome‘],singleRun: false }); }; 默认使用Chrome浏览器,可生成单元测试报告和覆盖率报告,覆盖率报告保存在根目录coverage文件夹内,启用autoWatch。 浏览器配置Karma支持的浏览器:
可同时配置多个浏览器进行测试,要启用其他浏览器,需安装依赖,比如启用Firefox: npm install karma-firefox-launcher --save-dev 然后在karma.conf.js内增加配置: ... require(‘karma-chrome-launcher‘),require(‘karma-firefox-launcher‘),... browsers: [‘Chrome‘,‘Firefox‘],... 运行测试用CLI创建App生成了一个单元测试文件app.component.spec.ts。执行CLI命令ng test即可运行单元测试: ng test 运行后在控制台输出测试结果并打开浏览器: 浏览器会显示测试结果,总测试数,失败数。在顶部,每个点或叉对应一个测试用例,点表示成功,叉表示失败,鼠标移到点或叉上会显示测试信息。点击测试结果中的某一行,可重新运行某个或某组(测试套件)测试。 常用参数: 自定义Launcherkarma-chrome-launcher、karma-firefox-launcher、karma-ie-launcher等均支持自定义Launcher,customLaunchers与--browsers结合使用可满足多种环境的测试需求。每种浏览器支持的自定义属性请查看Karma Browsers文档。 browsers: [‘Chrome‘],customLaunchers: { ChromeHeadlessCI: { base: ‘ChromeHeadless‘,flags: [‘--no-sandbox‘] } }, 运行如下命令进行测试: ng test --watch=false --progress=false --browsers=ChromeHeadlessCI 测试覆盖率运行如下命令生成测试覆盖率报告,报告保存在项目根目录下的coverage文件夹内: ng test --watch=false --code-coverage 如想每次测试都生成报告,可修改CLI配置文件angular.json: "test": { "options": { "codeCoverage": true } } 设置排除的文件或路径 ng test --watch=false --code-coverage --code-coverage-exclude=src/app/heroes/heroes.component.ts --code-coverage-exclude=src/app/hero-search/* 同样可以在angular.json中配置: "test": { "options": { "codeCoverage": true,"codeCoverageExclude": ["src/app/heroes/heroes.component.ts","src/app/hero-search/*"] } } 设定测试覆盖率指标 coverageIstanbulReporter: { reports: [ ‘html‘,‘lcovonly‘ ],fixWebpackSourcePaths: true,thresholds: { statements: 80,lines: 80,branches: 80,functions: 80 } } 测试报告中达到标准的背景为绿色: 注意:与CI集成时不要设置覆盖率指标,否则若未到达指标,Job会终止。 LCOV coverageIstanbulReporter中reports参数为[ ‘html‘,‘lcovonly‘ ],会生成html和lcov两种格式的报告。报告文件lcov.info可与Sonar集成,在Sonar管理界面配置LCOV Files路径,即可在Sonar中查看测试情况。 编写测试第一个测试使用CLI创建Service、Component等时会自动创建测试文件,我们以创建App时生成的测试文件app.component.spec.ts为例: import {async,TestBed} from ‘@angular/core/testing‘; import {RouterTestingModule} from ‘@angular/router/testing‘; import {AppComponent} from ‘./app.component‘; describe(‘AppComponent‘,() => { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ RouterTestingModule ],declarations: [ AppComponent ],}).compileComponents(); })); it(‘should create the app‘,() => { const fixture = TestBed.createComponent(AppComponent); const app = fixture.debugElement.componentInstance; expect(app).toBeTruthy(); }); it(`should have as title ‘hello‘`,() => { const fixture = TestBed.createComponent(AppComponent); const app = fixture.debugElement.componentInstance; expect(app.title).toEqual(‘hello‘); }); it(‘should render title in a h1 tag‘,() => { const fixture = TestBed.createComponent(AppComponent); fixture.detectChanges(); const compiled = fixture.debugElement.nativeElement; expect(compiled.querySelector(‘h1‘).textContent).toContain(‘Welcome to hello!‘); }); }); 测试结构 describe和it的第一个参数是测试的说明。it中可以包含一个或多个expect来执行测试验证。 TestBed TestBed.configureTestingModule()方法动态构建TestingModule来模拟Angular @NgModule, 支持@NgModule的大多数属性。 在测试中需导入必要的依赖:要测试的组件及依赖。在AppComponent页面中使用了router-outlet,因此我们导入了RouterTestingModule来模拟RouterModule。Test Module预配置了一些元素,比如BrowserModule,不需导入。 TestBed.createComponent()方法创建组件实例,返回ComponentFixture。ComponentFixture是一个测试工具(test harness),用于与创建的组件及相应的元素进行交互。 nativeElement和DebugElement 我们的测试样例仅运行在浏览器中,因此nativeElement总为HTMLElement,可以使用querySelector()、querySelectorAll()方法来查询元素。 element.querySelector(‘p‘); element.querySelector(‘input‘); element.querySelector(‘.welcome‘); element.querySelectorAll(‘span‘); detectChanges it(‘should render title in a h1 tag‘,() => { const fixture = TestBed.createComponent(AppComponent); fixture.detectChanges(); const compiled = fixture.debugElement.nativeElement; expect(compiled.querySelector(‘h1‘).textContent).toContain(‘Welcome to hello!‘); }); 当数据模型值改变后,也需调用fixture.detectChanges()方法: it(‘should render title in a h1 tag‘,() => { const fixture = TestBed.createComponent(AppComponent); const app = fixture.componentInstance; app.title = ‘china‘; fixture.detectChanges(); const compiled = fixture.nativeElement; expect(compiled.querySelector(‘h1‘).textContent).toContain(‘Welcome to china!‘); }); 可以配置自动检测,增加ComponentFixtureAutoDetect provider: import { ComponentFixtureAutoDetect } from ‘@angular/core/testing‘; ... TestBed.configureTestingModule({ providers: [ { provide: ComponentFixtureAutoDetect,useValue: true } ] }); 启用自动检测后仅需在数值改变后调用detectChanges(): it(‘should display original title‘,() => { // Hooray! No `fixture.detectChanges()` needed expect(h1.textContent).toContain(comp.title); }); it(‘should still see original title after comp.title change‘,() => { const oldTitle = comp.title; comp.title = ‘Test Title‘; // Displayed title is old because Angular didn‘t hear the change :( expect(h1.textContent).toContain(oldTitle); }); it(‘should display updated title after detectChanges‘,() => { comp.title = ‘Test Title‘; fixture.detectChanges(); // detect changes explicitly expect(h1.textContent).toContain(comp.title); }); 同步和异步beforeEach @Component({ selector: ‘app-banner‘,templateUrl: ‘./banner-external.component.html‘,styleUrls: [‘./banner-external.component.css‘] }) beforeEach(() => { TestBed.configureTestingModule({ declarations: [ BannerComponent ],}); fixture = TestBed.createComponent(BannerComponent); }); 当用CLI 的ng test命令运行含有如上同步beforeEach方法的测试时没有问题,因为会在运行测试之前先编译。若在非 CLI 环境下运行这些测试则可能失败。要解决这个问题,可以调用compileComponents()进行显示的编译。compileComponents()方法是异步的,必须在async()方法中调用: beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ RouterTestingModule ],declarations: [ AppComponent ],}).compileComponents(); })); 调用 compileComponents() 会关闭当前的 TestBed 实例,不再允许进行配置,不能再调用任何 TestBed 中的配置方法,既不能调 configureTestingModule(),也不能调用任何 override... 方法。 常同时使用同步beforeEach和异步beforeEach来协同工作,异步的 beforeEach() 负责编译组件,同步的 beforeEach() 负责执行其余的准备代码。测试运行器会先调用异步 beforeEach方法,运行完毕后再调用同步方法。 重构 import {async,ComponentFixture,() => { let fixture: ComponentFixture<AppComponent>; let app: AppComponent; beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ RouterTestingModule ],}).compileComponents(); })); beforeEach(() => { fixture = TestBed.createComponent(AppComponent); app = fixture.componentInstance; fixture.detectChanges(); }); it(‘should create the app‘,() => { expect(app).toBeTruthy(); }); it(`should have as title ‘hello‘`,() => { expect(app.title).toEqual(‘hello‘); }); it(‘should render title in a h1 tag‘,() => { const compiled = fixture.nativeElement; expect(compiled.querySelector(‘h1‘).textContent).toContain(‘Welcome to hello!‘); }); }); 也可以把这两个 beforeEach() 重整成一个异步的 beforeEach(): beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ RouterTestingModule ],}) .compileComponents() .then(() => { fixture = TestBed.createComponent(AppComponent); app = fixture.componentInstance; fixture.detectChanges(); }); })); 依赖注入与Mock对简单对象进行测试可以用new创建实例: describe(‘ValueService‘,() => { let service: ValueService; beforeEach(() => { service = new ValueService(); }); ... }); 不过大多数Service、Component等有多个依赖项,使用new很不方便。若用DI来创建测试对象,当依赖其他服务时,DI会找到或创建依赖的服务。要测试某个对象,在configureTestingModule中配置测试对象本身及依赖项,然后调用TestBed.get()注入测试对象: beforeEach(() => { TestBed.configureTestingModule({ providers: [ValueService] }); service = TestBed.get(ValueService); }); 单元测试的原则之一:仅对要测试对象本身进行测试,而不对其依赖项进行测试,依赖项通过mock方式注入,而不使用实际的对象,否则测试不可控。 Mock优先使用Spy方式: let masterService: MasterService; beforeEach(() => { const spy = jasmine.createSpyObj(‘ValueService‘,[‘getValue‘]); spy.getValue.and.returnValue(‘stub value‘); TestBed.configureTestingModule({ // Provide both the service-to-test and its (spy) dependency providers: [ MasterService,{ provide: ValueService,useValue: spy } ] }); masterService = TestBed.get(MasterService); }); HttpClient、Router、Location同测试含其它依赖的对象一样可以使用spy方式: beforeEach(() => { const httpClientSpy = jasmine.createSpyObj(‘HttpClient‘,[‘get‘]); TestBed.configureTestingModule({ providers: [ {provide: HttpClient,useValue: httpClientSpy} ] }); }); beforeEach(async(() => { const routerSpy = jasmine.createSpyObj(‘Router‘,[‘navigateByUrl‘]); const locationSpy = jasmine.createSpyObj(‘Location‘,[‘back‘]); TestBed.configureTestingModule({ providers: [ {provide: Router,useValue: routerSpy},{provide: Location,useValue: locationSpy} ] }) .compileComponents(); })); Component测试
测试组件类就像测试服务那样简单: export class WelcomeComponent implements OnInit { welcome: string; constructor(private userService: UserService) { } ngOnInit(): void { this.welcome = this.userService.isLoggedIn ? ‘Welcome,‘ + this.userService.user.name : ‘Please log in.‘; } } Mock类 class MockUserService { isLoggedIn = true; user = { name: ‘Test User‘}; }; 测试 ... beforeEach(() => { TestBed.configureTestingModule({ // provide the component-under-test and dependent service providers: [ WelcomeComponent,{ provide: UserService,useClass: MockUserService } ] }); // inject both the component and the dependent service. comp = TestBed.get(WelcomeComponent); userService = TestBed.get(UserService); }); ... it(‘should ask user to log in if not logged in after ngOnInit‘,() => { userService.isLoggedIn = false; comp.ngOnInit(); expect(comp.welcome).not.toContain(userService.user.name); expect(comp.welcome).toContain(‘log in‘); });
只涉及类的测试可以判断组件类的行为是否正常,但不能确定组件是否能正常渲染和交互。 TestBed.configureTestingModule({ declarations: [ BannerComponent ] }); const fixture = TestBed.createComponent(BannerComponent); const component = fixture.componentInstance; expect(component).toBeDefined(); dispatchEvent it(‘should convert hero name to Title Case‘,() => { // get the name‘s input and display elements from the DOM const hostElement = fixture.nativeElement; const nameInput: HTMLInputElement = hostElement.querySelector(‘input‘); const nameDisplay: HTMLElement = hostElement.querySelector(‘span‘); nameInput.value = ‘quick BROWN fOx‘; // dispatch a DOM event so that Angular learns of input value change. nameInput.dispatchEvent(newEvent(‘input‘)); fixture.detectChanges(); expect(nameDisplay.textContent).toBe(‘Quick Brown Fox‘); }); 嵌套组件组件中常常使用其他组件: <app-banner></app-banner> <app-welcome></app-welcome> <nav> <a routerLink="/dashboard">Dashboard</a> <a routerLink="/heroes">Heroes</a> <a routerLink="/about">About</a> </nav> <router-outlet></router-outlet> 对于无害的内嵌组件可以直接将其添加到declarations中,这是最简单的方式: describe(‘AppComponent & TestModule‘,() => { beforeEach(async(() => { TestBed.configureTestingModule({ declarations: [ AppComponent,BannerComponent,WelcomeComponent ] }) .compileComponents().then(() => { fixture = TestBed.createComponent(AppComponent); comp = fixture.componentInstance; }); })); ... }); 也可为无关紧要的组件创建一些测试桩: @Component({selector: ‘app-banner‘,template: ‘‘}) class BannerStubComponent {} @Component({selector: ‘router-outlet‘,template: ‘‘}) class RouterOutletStubComponent { } @Component({selector: ‘app-welcome‘,template: ‘‘}) class WelcomeStubComponent {} 然后在TestBed的配置中声明它们: TestBed.configureTestingModule({ declarations: [ AppComponent,BannerStubComponent,RouterOutletStubComponent,WelcomeStubComponent ] }) 另一种办法是使用NO_ERRORS_SCHEMA,要求 Angular编译器忽略那些不认识的元素和属性: TestBed.configureTestingModule({ declarations: [ AppComponent,RouterLinkDirectiveStub ],schemas: [ NO_ERRORS_SCHEMA ] }) NO_ERRORS_SCHEMA方法比较简单,但不要过度使用。NO_ERRORS_SCHEMA 会阻止编译器因疏忽或拼写错误而缺失的组件和属性,如人工找出这些 bug会很费时。 属性指令测试import { Directive,ElementRef,Input,OnChanges } from ‘@angular/core‘; @Directive({ selector: ‘[highlight]‘ }) /** Set backgroundColor for the attached element to highlight color and set the element‘s customProperty to true */ export class HighlightDirective implements OnChanges { defaultColor = ‘rgb(211,211,211)‘; // lightgray @Input(‘highlight‘) bgColor: string; constructor(private el: ElementRef) { el.nativeElement.style.customProperty = true; } ngOnChanges() { this.el.nativeElement.style.backgroundColor = this.bgColor || this.defaultColor; } } 属性型指令肯定要操纵 DOM,如只针对类测试不能证明指令的有效性。若通过组件来测试,单一的用例一般无法探索指令的全部能力。因此,更好的方法是创建一个能展示该指令所有用法的人造测试组件: @Component({ template: ` <h2 highlight="yellow">Something Yellow</h2> <h2 highlight>The Default (Gray)</h2> <h2>No Highlight</h2> <input #box [highlight]="box.value" value="cyan"/>` }) class TestComponent { } 测试程序: beforeEach(() => { fixture = TestBed.configureTestingModule({ declarations: [ HighlightDirective,TestComponent ] }) .createComponent(TestComponent); fixture.detectChanges(); // initial binding // all elements with an attached HighlightDirective des = fixture.debugElement.queryAll(By.directive(HighlightDirective)); // the h2 without the HighlightDirective bareH2 = fixture.debugElement.query(By.css(‘h2:not([highlight])‘)); }); // color tests it(‘should have three highlighted elements‘,() => { expect(des.length).toBe(3); }); it(‘should color 1st <h2> background "yellow"‘,() => { const bgColor = des[0].nativeElement.style.backgroundColor; expect(bgColor).toBe(‘yellow‘); }); it(‘should color 2nd <h2> background w/ default color‘,() => { const dir = des[1].injector.get(HighlightDirective) as HighlightDirective; const bgColor = des[1].nativeElement.style.backgroundColor; expect(bgColor).toBe(dir.defaultColor); }); it(‘should bind <input> background to value color‘,() => { // easier to work with nativeElement const input = des[2].nativeElement as HTMLInputElement; expect(input.style.backgroundColor).toBe(‘cyan‘,‘initial backgroundColor‘); // dispatch a DOM event so that Angular responds to the input value change. input.value = ‘green‘; input.dispatchEvent(newEvent(‘input‘)); fixture.detectChanges(); expect(input.style.backgroundColor).toBe(‘green‘,‘changed backgroundColor‘); }); it(‘bare <h2> should not have a customProperty‘,() => { expect(bareH2.properties[‘customProperty‘]).toBeUndefined(); }); Pipe测试describe(‘TitleCasePipe‘,() => { // This pipe is a pure,stateless function so no need for BeforeEach let pipe = new TitleCasePipe(); it(‘transforms "abc" to "Abc"‘,() => { expect(pipe.transform(‘abc‘)).toBe(‘Abc‘); }); it(‘transforms "abc def" to "Abc Def"‘,() => { expect(pipe.transform(‘abc def‘)).toBe(‘Abc Def‘); }); ... }); Testing ModuleRouterTestingModule beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ RouterTestingModule ],}).compileComponents(); })); RouterTestingModule还可以模拟路由: beforeEach(() => { TestBed.configureTestModule({ imports: [ RouterTestingModule.withRoutes( [{path: ‘‘,component: BlankCmp},{path: ‘simple‘,component: SimpleCmp}] ) ] }); }); HttpClientTestingModule describe(‘HttpClient testing‘,() => { let httpClient: HttpClient; let httpTestingController: HttpTestingController; beforeEach(() => { TestBed.configureTestingModule({ imports: [ HttpClientTestingModule ] }); // Inject the http service and test controller for each test httpClient = TestBed.get(HttpClient); httpTestingController = TestBed.get(HttpTestingController); }); afterEach(() => { // After every test,assert that there are no more pending requests. httpTestingController.verify(); }); it(‘can test HttpClient.get‘,() => { const testData: Data = {name: ‘Test Data‘}; // Make an HTTP GET request httpClient.get<Data>(testUrl) .subscribe(data => // When observable resolves,result should match test data expect(data).toEqual(testData) ); // The following `expectOne()` will match the request‘s URL. // If no requests or multiple requests matched that URL // `expectOne()` would throw. const req = httpTestingController.expectOne(‘/data‘); // Assert that the request is a GET. expect(req.request.method).toEqual(‘GET‘); // Respond with mock data,causing Observable to resolve. // Subscribe callback asserts that correct data was returned. req.flush(testData); // Finally,assert that there are no outstanding requests. httpTestingController.verify(); }); ... }); 调试在测试结果浏览器中,点击“DEBUG”按钮会打开新浏标签页并重新运行测试程序。按"F12"打开调试界面,然后进入Sources找到测试文件(CTRL+P),在测试程序中设置断点即可调试。 配置E2E测试E2E测试使用Jasmine和Protractor测试框架,Protractor是Angular端到端测试框架。 安装Protractornpm install -g protractor 在项目中执行npm install时会安装protractor,不必单独执行以上命令。安装protractor后会安装两个命令行工具protractor和webdriver-manager(位于node_modulesprotractorbin目录),webdriver-manager负责管理驱动、启停Selenium Server。 webdriver-manager命令: clean removes all downloaded driver files from the out_dir start start up the selenium server shutdown shut down the selenium server status list the current available drivers update install or update selected binaries,更新的驱动保存在node_modulesprotractornode_moduleswebdriver-managerselenium目录下 version get the current version 配置文件使用CLI创建的App会生成一个e2e项目,其中包含测试配置protractor.conf.js及测试代码。 const { SpecReporter } = require(‘jasmine-spec-reporter‘); exports.config = { allScriptsTimeout: 11000,specs: [ ‘./src/**/*.e2e-spec.ts‘ ],capabilities: { ‘browserName‘: ‘chrome‘ },directConnect: true,baseUrl: ‘http://localhost:4200/‘,framework: ‘jasmine‘,jasmineNodeOpts: { showColors: true,defaultTimeoutInterval: 30000,print: function() {} },onPrepare() { require(‘ts-node‘).register({ project: require(‘path‘).join(__dirname,‘./tsconfig.e2e.json‘) }); jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); } }; 默认,Protractor使用Jasmine测试框架,使用直连方式连接Chrome浏览器,测试文件扩展名为.e2e-spec.ts。 浏览器配置Protractor支持Chrome、Firefox、Safari、IE等浏览器。 multiCapabilities: [{ browserName: ‘firefox‘ },{ browserName: ‘chrome‘ }] 另外需在package.json中增加配置: "scripts": { "webdriver-update": "webdriver-manager update" } 在运行测试前执行: npm run webdriver-update 否则项目中的驱动不会更新(默认只有chrome驱动,在命令行运行webdriver-manager update仅更新全局的驱动),运行测试会报如下错误: No update-config.json found. Run ‘webdriver-manager update‘ to download binaries 浏览器选项 capabilities: { ‘browserName‘: ‘chrome‘,‘chromeOptions‘: { ‘args‘: [‘show-fps-counter=true‘] } }, capabilities: { ‘browserName‘: ‘firefox‘,‘moz:firefoxOptions‘: { ‘args‘: [‘--safe-mode‘] } }, 更多选项请查看相应驱动ChromeDriver、GeckoDriver。 Selenium Server配置使用Standalone Selenium Server时,需安装JDK。 webdriver-manager update webdriver-manager start 删除原配置中的directConnect、baseUrl: directConnect: true, 增加seleniumAddress(默认为http://localhost:4444/wd/hub): seleniumAddress: ‘http://localhost:4444/wd/hub‘, 运行测试执行CLI命令 ng e2e即可运行E2E测试: ng e2e 常用参数: --base-url Base URL for protractor to connect to. --configuration (-c) A named configuration environment,as specified in the "configurations" section of angular.json. --host Host to listen on. --port The port to use to serve the application. --prod When true,sets the build configuration to the production environment. --protractor-config The name of the Protractor configuration file. --webdriver-update Try to update webdriver. 指定配置文件不同的环境若配置不同,可使用不同的配置文件。 比如,在CI环境中启用Chrome Headless模式: const config = require(‘./protractor.conf‘).config; config.capabilities = { browserName: ‘chrome‘,chromeOptions: { args: [‘--headless‘,‘--no-sandbox‘] } }; exports.config = config; 注意: windows系统要增加参数--disable-gpu 运行以下命令测试: ng e2e --protractor-config=e2eprotractor-ci.conf.js 编写E2E测试第一个测试import { AppPage } from ‘./app.po‘; describe(‘workspace-project App‘,() => { let page: AppPage; beforeEach(() => { page = new AppPage(); }); it(‘should display welcome message‘,() => { page.navigateTo(); expect(page.getTitleText()).toEqual(‘Welcome to hello!‘); }); }); import { browser,by,element } from ‘protractor‘; export class AppPage { navigateTo() { return browser.get(‘/‘); } getTitleText() { return element(by.css(‘app-root h1‘)).getText(); } } E2E测试与单元测试都使用了Jasmine,测试结构相同。Protractor提供了全局的browser、element、by,分别用来打开页面和查找元素。 Protractordescribe(‘Protractor Demo App‘,function() { it(‘should add one and two‘,function() { browser.get(‘http://juliemr.github.io/protractor-demo/‘); element(by.model(‘first‘)).sendKeys(1); element(by.model(‘second‘)).sendKeys(2); element(by.id(‘gobutton‘)).click(); expect(element(by.binding(‘latest‘)).getText()). toEqual(‘5‘); // This is wrong! }); });
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |