问题描述
我想对服务进行单元测试,但是,在运行测试时,出现以下错误:
I'd like to unit test a service, however, when running the test, I get the following error:
相应的行(auth.service.ts:217
)在下面的代码中突出显示.运行该应用程序可以正常运行,因此,我看不出测试失败的明显原因.
The corresponding line (auth.service.ts:217
) is highlighted below in code. Running the application works perfectly fine, therefore I do not see an obvious reason for the test to fail.
NB:这篇SO帖子提示我m将对象解析两次.但是,当运行应用程序时,它也不应该失败吗?
NB: This SO post suggests that I'm parsing the object twice. But shouldn't it fail when running the application then, too?
auth.service.ts
public login(username: string, password: string): Observable<User> {
// ...
return this.http.request(path, requestOptions).map((response: Response) => {
if (response.status === 200) {
const token = response.json().token; // <<-- Uncaught (in promise) SyntaxError: Unexpected token o in JSON at position 1
const user = this.extractUser(response);
return user;
}
return null;
})
.catch(this.handleError);
}
auth.service.spec.ts
describe('AuthService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [
AuthService,
MockBackend,
BaseRequestOptions,
{
provide: Http,
useFactory: (backend: MockBackend, options: BaseRequestOptions) => new Http(backend, options),
deps: [MockBackend, BaseRequestOptions]
}
],
imports: [
RouterTestingModule
],
});
});
it('should return an Observable<User>', inject([AuthService, MockBackend], (authService: AuthService, mockBackend: MockBackend) => {
mockBackend.connections.subscribe((connection: any) => {
connection.mockRespond(new Response(new ResponseOptions({
body: '{"token": "abc123", "name":"Jeff"}'
})));
});
authService.login('[email protected]', 'password').subscribe(user => {
expect(user.name).toEqual('Jeff');
});
}));
});
记录响应将输出以下内容:
Logging the response outputs the following:
Response
body: ReadableStream
locked: true
__proto__: Object
bodyUsed: true
headers: Headers
__proto__: Headers
ok: true
redirected: false
status: 200
statusText: "OK"
type: "default"
url: ""
__proto__: Response
推荐答案
错误Unexpected token ... in JSON at position 1
实际上意味着JSON.parse
应用于了无效JSON的内容-随机字符串或非字符串值所有这些都被强制转换为字符串.
The error Unexpected token ... in JSON at position 1
actually means that JSON.parse
was applied to something that is not valid JSON - a random string or a value that is not a string at all which was coerced to string.
消息Unexpected token o ...
暗示解析的值很可能是对象-被强制为[object ...]
字符串.
The message Unexpected token o ...
implies that parsed value was most likely an object - which is coerced to [object ...]
string.
问题在这里清楚可见:
Response
body: ReadableStream
locked: true
__proto__: Object
bodyUsed: true
...
此处的响应对象是全局 Response
构造函数的实例(Fetch API的一部分),以及 ReadableStream
清楚地表明了这一点.
Response object here is an instance of global Response
constructor (a part of Fetch API), and the presence of ReadableStream
clearly indicates this.
在获取polyfill"中可以看到 ,res.json()
所做的只是将JSON.parse
应用于某个值
As it can be seen in Fetch polyfill, all that res.json()
does is applying JSON.parse
to some value
this.json = function() {
return this.text().then(JSON.parse)
}
这可能是错误地提供给全局Response
构造函数的new ResponseOptions
对象,因此会出现错误.
which is likely new ResponseOptions
object that was erroneously supplied to global Response
constructor, hence the error.
Angular类似地命名为 Response
类从Fetch Response
派生其接口,但显然不兼容.问题在于它从未被导入过,因此使用了全局Response
.
Angular has similarly named Response
class which derives its interface from Fetch Response
but obviously isn't compatible. The problem is that it was never imported and thus global Response
was used instead.
应该是
import { Response, ResponseOptions, ... } from '@angular/http';
如何预防
全局变量是在Typescript类型定义中声明的,它们不能被取消声明,但可以在自定义类型定义中重新声明:
How to prevent
Globals are declared in Typescript type definitions, they cannot be undeclared but can be re-declared in custom type definition:
custom.d.ts
declare var Headers: undefined;
declare var Request: undefined;
declare var Response: undefined;
declare var URLSearchParams: undefined;
使用全局变量而不是导入的同名Http类将导致类型错误:
Using globals instead of imported Http classes of the same name will result in type error:
只要Angular应用中未使用Fetch API,这是理想的行为.
Which is a desirable behaviour as long as Fetch API isn't used in Angular app.
对于HttpClient
来说,这不是问题,它取代了Angular 4.3中的Http
,并且不使用与Fetch API中的名称相同的类.
This is not an issue for HttpClient
that replaced Http
in Angular 4.3 and doesn't use classes of same names as the ones from Fetch API.
这篇关于单元测试时出错:“未捕获(承诺)语法错误:JSON中位置1的意外令牌o";的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!