为啥我的单元测试在 Chrome 中通过而在 PhantomJS 中失败?
Posted
技术标签:
【中文标题】为啥我的单元测试在 Chrome 中通过而在 PhantomJS 中失败?【英文标题】:Why do my unit tests pass with Chrome and fail with PhantomJS?为什么我的单元测试在 Chrome 中通过而在 PhantomJS 中失败? 【发布时间】:2017-02-17 21:14:59 【问题描述】:我正在使用 Angular2 final (2.0.2) 和 angular-cli。 我正在尝试将其设置为使用 PhantomJS 运行单元测试。 使用 Chrome 和 karma-chrome-launcher 运行规范 - 所有测试都通过。 使用 Phantomjs-prebuilt 2.1.13 和 karma-phantomjs-launcher 1.0.2 测试失败。
我将 phantomjs 启动器添加到 karma.conf 中的 plugins 数组,以及 browsers 数组中的 PahntomJS。
我得到的错误是:
PhantomJS 2.1.1 (Mac OS X 0.0.0) DataTableFormat 应该转换日期 以毫秒为单位失败 ReferenceError:找不到变量:src/main/js/test.ts 中的 Intl(第 53565 行) intlDateFormat@webpack:///Users/sninio/dev/csp-ui/~/@angular/common/src/facade/intl.js:117:0
也许我在 angular-cli 创建的 test.ts 文件中遗漏了一些配置?
更新:
似乎只有导入 DatePipe
和 JsonPipe
失败的测试。
我也尝试在 test.ts
中导入 @angular/common/testing
但这无济于事 - 它们没有在相关的 index.js 中导出。
还尝试导入整个@angular/common/pipes
,但这也不起作用。
这是管道:
import Pipe, PipeTransform from "@angular/core";
import DatePipe, JsonPipe from "@angular/common";
@Pipe(name: 'dataTableFormat')
export class DataTablePipe implements PipeTransform
// values with type 'json' are parsed to json. As a result, string values may be displayed with quotes ("<string>").
// To avoid that, we remove these quotes with this regex
private quotesExp: RegExp = /^\"|\"$/gi;
constructor(private datePipe: DatePipe, private jsonPipe: JsonPipe)
transform(value: any, type: string): string
switch (type)
case "date":
return this.datePipe.transform(value, 'short');
case "json":
return this.jsonPipe.transform(value).replace(this.quotesExp, "");
default:
return value;
和规格:
import inject, TestBed from "@angular/core/testing";
import DataTablePipe from "./data-table.pipe";
import DatePipe, JsonPipe from "@angular/common";
describe('DataTableFormat', () =>
beforeEach(() =>
TestBed.configureTestingModule(
providers: [
DatePipe, JsonPipe
]
);
);
it('should transform date in milliseconds', inject([DatePipe, JsonPipe], (datePipe, jsonPipe) =>
let pipe = new DataTablePipe(datePipe, jsonPipe);
let testDate: Date = new Date();
expect(pipe.transform(testDate.getTime(), 'date')).toBe(datePipe.transform(testDate, 'short'));
));
it('should transform date string', inject([DatePipe, JsonPipe], (datePipe, jsonPipe) =>
let pipe = new DataTablePipe(datePipe, jsonPipe);
let testDate: Date = new Date();
expect(pipe.transform(testDate.toISOString(), 'date')).toBe(datePipe.transform(testDate, 'short'));
));
it('should transform json', inject([DatePipe, JsonPipe], (datePipe, jsonPipe) =>
let pipe = new DataTablePipe(datePipe, jsonPipe);
let testJson =
prop1: "val1",
prop2: "val2"
;
expect(pipe.transform(testJson, 'json')).toBe(jsonPipe.transform(testJson));
));
);
这是我的test.ts
文件 - 与angular-cli
生成的文件相比没有太大变化...
import "./polyfills.ts";
import "zone.js/dist/long-stack-trace-zone";
import "zone.js/dist/proxy.js";
import "zone.js/dist/sync-test";
import "zone.js/dist/jasmine-patch";
import "zone.js/dist/async-test";
import "zone.js/dist/fake-async-test";
// Unfortunately there's no typing for the `__karma__` variable. Just declare it as any.
declare var __karma__: any;
declare var require: any;
// Prevent Karma from running prematurely.
__karma__.loaded = function ()
;
//noinspection TypeScriptUnresolvedVariable
Promise.all([
System.import('@angular/core/testing'),
System.import('@angular/platform-browser-dynamic/testing'),
System.import('../../../node_modules/nvd3/build/nv.d3.min.js'),
])
// First, initialize the Angular testing environment.
.then(([testing, testingBrowser]) =>
testing.getTestBed().initTestEnvironment(
testingBrowser.BrowserDynamicTestingModule,
testingBrowser.platformBrowserDynamicTesting()
);
)
// Then we find all the tests.
.then(() => require.context('./', true, /\.spec\.ts/))
// And load the modules.
.then(context => context.keys().map(context))
// Finally, start Karma to run the tests.
.then(__karma__.start, __karma__.error);
知道为什么这适用于 Chrome 而不是 PhantomJS 吗?
【问题讨论】:
如果你使用TestBed
而不是inject
和new
来创建你的管道呢?
它实际上与注入无关 - 我弄错了。其他测试也失败了。
那么请给minimal reproducible example。
我链接到原始帖子中的代码。很难举个例子,因为就像我说的那样,测试在 Chrome 上工作,而不是在 PhantomJS 上。我可能会在 main.ts 中丢失一些映射或导入失败,但不确定是怎么回事,因为它们在 Chrome 中传递。
在问题本身。另外,当您询问配置时,显示配置。
【参考方案1】:
Intl 实现在 Angular 中可用,在 PhantomJS 中不可用。要使其与 polyfill 一起使用,请按照以下步骤操作:
-
安装 Intl:npm install intl --save
将以下导入添加到 polyfills.ts 文件中:
进口'国际'; 导入'intl/locale-data/jsonp/en.js';
【讨论】:
【参考方案2】:现在您的所有浏览器都支持 Intl。 polyfill.io 是一个漂亮的服务,它只会在请求的浏览器确实需要它时才加载 polyfill。这是一个很好的解决方案,但是如果你希望你的 polyfill 与你的脚本捆绑在一起呢?您可能会获得更好的性能,并且您的应用程序不依赖第三方 CDN,如果第三方 CDN 出现故障,您的应用程序也会随之关闭。那么下一个选项是什么?
使用 Angular CLI 实际上非常简单。首先,我们将使用 npm 将 Intl polyfill 直接安装到我们的 Angular 应用程序中。为此,请运行 npm install intl --save。一旦安装在您的 Angular CLI 项目中,请转到 /src/polyfills.ts 文件。在这里您可以添加以下行。
import 'intl';
import 'intl/locale-data/jsonp/en.js';
就是这样!现在,当您的项目构建时,它将添加 Intl polyfill 和英语语言服务。您可以通过导入更多语言文件来添加更多语言支持。现在这样做的缺点是即使浏览器支持 Intl 它仍然必须下载代码。您可以使用功能检测和动态加载来缓解这种情况。 polyfill 最重要的一点是,随着浏览器对 Intl 的支持越来越好,我们将能够完全放弃依赖!
【讨论】:
【参考方案3】:由于 PhantomJS 没有实现 Angular2 所依赖的 Intl
实现,解决方案是安装 npm 包 intl polyfill 并编辑 polyfills.ts
以包含
import 'intl';
import 'intl/locale-data/jsonp/en.js';
请看这里:https://github.com/angular/angular/issues/3333 在这里:https://github.com/angular/angular/issues/10809 在这里:https://coryrylan.com/blog/adding-the-internationalization-polyfill-to-a-angular-cli-project
【讨论】:
这很酷,但是因为您专门为 PhantomJS 进行 polyfill,所以我建议您将导入(包括您依赖的其他语言环境)添加到您的test.ts
文件中。
我在我的 test.ts 'import 'intl/locale-data/jsonp/en'中添加了这个;'它在本地工作正常,但在服务器上它不工作。在添加到 polyfils.ts 之后,这里也是 polyfills.ts 部分 **import 'intl'; ** ** 导入 'intl/locale-data/jsonp/en'; **以上是关于为啥我的单元测试在 Chrome 中通过而在 PhantomJS 中失败?的主要内容,如果未能解决你的问题,请参考以下文章
使用 Detox 在 Android React Native 应用程序中通过 Chrome 弹出测试登录
为啥 false++ 在 Firefox 中会产生 SyntaxError 而在 Chrome 中会产生 ReferenceError?
为啥我的添加好友测试路由在 insomina 中通过了 200 OK,但是当我调用获取所有用户时它没有嵌套?