单元测试时出错:“Uncaught (in promise) SyntaxError: Unexpected token o in JSON at position 1" [英] Error when unit testing: "Uncaught (in promise) SyntaxError: Unexpected token o in JSON at position 1"
问题描述
我想对服务进行单元测试,但是,在运行测试时,我收到以下错误:
I'd like to unit test a service, however, when running the test, I get the following error:
Uncaught (in promise) SyntaxError: Unexpected token o in JSON at位置 1在 MapSubscriber.project (auth.service.ts:217)在 MapSubscriber.Array.concat.MapSubscriber._next (map.js:77)在 MapSubscriber.Array.concat.Subscriber.next (Subscriber.js:89)在 TakeSubscriber.Array.concat.TakeSubscriber._next (take.js:80)在 TakeSubscriber.Array.concat.Subscriber.next (Subscriber.js:89)在 ReplaySubject.Array.concat.ReplaySubject._subscribe (ReplaySubject.js:55)在 ReplaySubject.Array.concat.Observable._trySubscribe (Observable.js:57)在 ReplaySubject.Array.concat.Subject._trySubscribe (Subject.js:97)在 ReplaySubject.Array.concat.Observable.subscribe (Observable.js:45)在 TakeOperator.Array.concat.TakeOperator.call (take.js:60)在 AnonymousSubject.Array.concat.Observable.subscribe (Observable.js:42)在 MapOperator.Array.concat.MapOperator.call (map.js:54)在 AnonymousSubject.Array.concat.Observable.subscribe (Observable.js:42)在 CatchOperator.Array.concat.CatchOperator.call (catch.js:79)在 AnonymousSubject.Array.concat.Observable.subscribe (Observable.js:42)
Uncaught (in promise) SyntaxError: Unexpected token o in JSON at position 1 at MapSubscriber.project (auth.service.ts:217) at MapSubscriber.Array.concat.MapSubscriber._next (map.js:77) at MapSubscriber.Array.concat.Subscriber.next (Subscriber.js:89) at TakeSubscriber.Array.concat.TakeSubscriber._next (take.js:80) at TakeSubscriber.Array.concat.Subscriber.next (Subscriber.js:89) at ReplaySubject.Array.concat.ReplaySubject._subscribe (ReplaySubject.js:55) at ReplaySubject.Array.concat.Observable._trySubscribe (Observable.js:57) at ReplaySubject.Array.concat.Subject._trySubscribe (Subject.js:97) at ReplaySubject.Array.concat.Observable.subscribe (Observable.js:45) at TakeOperator.Array.concat.TakeOperator.call (take.js:60) at AnonymousSubject.Array.concat.Observable.subscribe (Observable.js:42) at MapOperator.Array.concat.MapOperator.call (map.js:54) at AnonymousSubject.Array.concat.Observable.subscribe (Observable.js:42) at CatchOperator.Array.concat.CatchOperator.call (catch.js:79) at AnonymousSubject.Array.concat.Observable.subscribe (Observable.js:42)
相应的行 (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.
注意:这篇 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('jeff@example.com', '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.
在 Fetch 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:
TS2532:对象可能是未定义".
TS2532: Object is possibly 'undefined'.
只要 Fetch API 不在 Angular 应用程序中使用,这是一种理想的行为.
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.
这篇关于单元测试时出错:“Uncaught (in promise) SyntaxError: Unexpected token o in JSON at position 1"的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!