You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AngularJS迁移至Angular 5后Protractor测试适配问题求助

我之前经手过AngularJS到Angular 5的UI库迁移,也踩过不少Protractor测试适配的坑,结合你贴的新旧代码,给你梳理下核心的调整方向和具体修改点:

一、定位策略的核心调整

Angular 5的内容投影机制(ng-content)和AngularJS的ng-transclude差异很大,直接导致测试里的元素选择器大部分需要修改:

  • 内容区域选择器:原来AngularJS测试里用的.rt-card__content > rt-card-content会失效——因为Angular的ng-content会把投影内容直接注入到.rt-card__content容器内,不再保留rt-card-content标签。需要改成直接定位容器本身:.rt-card__content。
  • 链接区域选择器:原代码里的.rt-card__footer > rt-card-link > a要替换成.rt-card__footer > rt-card-footer > a,因为你新的Angular模板里用的投影选择器是rt-card-footer(对应旧代码的rtCardLink)。
  • 属性绑定验证:虽然data-rt-id的生成逻辑(rtId + 'Title')和旧代码({{::$ctrl.rtId}}Title)一致,但如果测试里要定位带data-rt-id的元素,确保选择器格式正确(比如[data-rt-id='default-cardTitle'])。
二、测试代码的API与风格升级

Angular 5对应的Protractor版本已经支持ES6+的异步语法,建议把旧的Promise回调改成async/await,让测试代码更简洁易读:

修改测试组件类的方法

比如把原来的getTitleText()从回调风格改成async/await:

// 旧代码
getTitleText(): promise.Promise<string> {
  return this.component.element(by.css(this.titleElementSelector)).getText().then((text) => {
    return text ? text.trim() : '';
  });
}

// 新代码
async getTitleText(): Promise<string> {
  const text = await this.component.element(by.css(this.titleElementSelector)).getText();
  return text ? text.trim() : '';
}

修改测试用例的执行逻辑

所有测试步骤都要改成异步等待,避免Protractor的同步问题:

// 旧代码
beforeAll(() => {
  page = new CardPage();
});

// 新代码
beforeAll(async () => {
  page = new CardPage();
  await browser.get('#/components/card');
});

// 测试用例示例
it('should contain the correct title text', async () => {
  expect(await page.defaultCard.getTitleText()).toEqual('Time off', `Title text is not correct`);
});
三、Protractor与Angular 5的同步配置

确保你的Protractor配置文件(protractor.conf.js)适配Angular 5:

  • 检查rootElement配置是否指向你的Angular应用根组件(比如app-root),Protractor需要通过它来识别Angular应用并同步异步操作。
  • 如果测试中用到了非Angular的第三方组件,需要临时禁用Angular同步:
await browser.waitForAngularEnabled(false);
// 执行非Angular元素操作
await browser.waitForAngularEnabled(true);
四、针对你提供代码的完整修改示例

测试用的CardComponent类修改

import {element, by, ElementFinder} from 'protractor';

export interface ICard {
  isPresent(): Promise<boolean>;
  getTitleText(): Promise<string>;
  getContentHtml(): Promise<string>;
  getLinkText(): Promise<string>;
  getLinkUrl(): Promise<string>;
}

export class CardComponent implements ICard {
  private readonly titleElementSelector: string = '.rt-card__title';
  private readonly contentElementSelector: string = '.rt-card__content'; // 修正选择器
  private readonly linkElementSelector: string = '.rt-card__footer > rt-card-footer > a'; // 修正选择器
  private component: ElementFinder;

  constructor(selector: string) {
    this.component = element(by.css(`rt-card${selector}`));
  }

  async isPresent(): Promise<boolean> {
    return this.component.isPresent();
  }

  async getTitleText(): Promise<string> {
    const text = await this.component.element(by.css(this.titleElementSelector)).getText();
    return text ? text.trim() : '';
  }

  async getContentHtml(): Promise<string> {
    const html = await this.component.element(by.css(this.contentElementSelector)).getAttribute('innerHTML');
    return html.trim();
  }

  async getLinkText(): Promise<string> {
    return this.component.element(by.css(this.linkElementSelector)).getText();
  }

  async getLinkUrl(): Promise<string> {
    return this.component.element(by.css(this.linkElementSelector)).getAttribute('href');
  }
}

功能测试用例修改

import CardPage from './card.page';

let page;

describe('Card', () => {
  beforeAll(async () => {
    page = new CardPage();
    await browser.get('#/components/card');
  });

  it('should be available on the page', async () => {
    expect(await page.defaultCard.isPresent()).toBe(true, `Can't find the default card`);
  });

  it('should contain the correct title text', async () => {
    expect(await page.defaultCard.getTitleText()).toEqual('Time off', `Title text is not correct`);
  });

  it('should contain the correct content', async () => {
    expect(await page.defaultCard.getContentHtml()).toEqual(`<span>0 hours available</span>`, `Content HTML is not correct`);
  });

  it('should contain the correct link', async () => {
    expect(await page.defaultCard.getLinkText()).toEqual(`Go to time off`, `Link text is not correct`);
    expect(await page.defaultCard.getLinkUrl()).toEqual(`http://www.google.com/`, `Link URL is not correct`);
  });
});
额外注意事项
  • 升级Protractor到支持Angular 5的版本(建议v5.x及以上),避免版本兼容问题。
  • 如果遇到元素超时未出现的问题,可使用Protractor的ExpectedConditions来等待元素:
import {ExpectedConditions} from 'protractor';

await browser.wait(ExpectedConditions.presenceOf(this.component), 5000, 'Card component not found');

内容的提问来源于stack exchange,提问作者rf2018

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:44:43