我想对服务进行单元测试,但是,在运行测试时,我收到以下错误:
Uncaught(在promise中)SyntaxError:JSON中的意外标记o 位置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) at AnonymousSubject.Array.concat.Observable.subscribe(Observable.js:42)
相应的行(auth.service.ts:217
)在代码中突出显示如下。运行应用程序非常正常,因此我没有看到测试失败的明显原因。
注意:This SO post表示我正在解析对象两次。但是,当运行应用程序时,它不应该失败吗?
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');
});
}));
});
记录响应输出如下:
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
答案 0 :(得分:16)
错误Unexpected token ... in JSON at position 1
实际上意味着JSON.parse
被应用于无效JSON的东西 - 一个随机字符串或一个完全不是字符串的值,它被强制转换为字符串。
消息Unexpected token o ...
暗示解析的值很可能是一个对象 - 它被强制转换为[object ...]
字符串。
这里可以清楚地看到问题:
Response
body: ReadableStream
locked: true
__proto__: Object
bodyUsed: true
...
此处的响应对象是全局Response
constructor(Fetch API的一部分)的实例,ReadableStream
的存在清楚地表明了这一点。
As it can be seen in Fetch polyfill,res.json()
所做的就是将JSON.parse
应用于某个值
this.json = function() {
return this.text().then(JSON.parse)
}
可能new ResponseOptions
对象被错误地提供给全局Response
构造函数,因此出错。
Angular类似地命名为Response
class,它从Fetch Response
派生出其接口,但显然不兼容。问题是它从未导入,因此使用了全局Response
。
应该是
import { Response, ResponseOptions, ... } from '@angular/http';
Globals在Typescript类型定义中声明,它们不能是未声明的,但可以在自定义类型定义中重新声明:
custom.d.ts
declare var Headers: undefined;
declare var Request: undefined;
declare var Response: undefined;
declare var URLSearchParams: undefined;
使用全局变量而不是同名的导入的Http类将导致类型错误:
TS2532:对象可能未定义&#39;。
只要在Angular应用中未使用Fetch API,这是一种理想的行为。
HttpClient
替换了Angular 4.3中的Http
,并且没有使用与Fetch API 相同名称的类,这不是问题。< / p>
答案 1 :(得分:2)
SyntaxError:位置1的JSON中的意外标记o
错误的原因:
Content-Type
作为JSON
作为API
的回复,但您的回复为String
字母o
的开头。因此,它会引发错误Unexpected token o in JSON at position 1
。text/html
,则需要解析,如果响应标头为application/json
,则已经为您解析了。如果您再次解析它,它将为您提供unexpected token o
如果响应已经是JSON对象,则无需使用response.json()
。
答案 2 :(得分:0)
无需解析数据。
通常,当您遇到此错误时,表示您不需要解析数据。
尝试使用&#39;令牌&#39;直。
为了理智,请在控制台中打印数据。 (你也可以对它进行字符串化并打印出来,看看它给你的东西)
答案 3 :(得分:0)
事实证明我错过了Response
的导入:
之前:import { BaseRequestOptions, Http, ResponseOptions } from '@angular/http';
之后:import { BaseRequestOptions, Http, Response, ResponseOptions } from '@angular/http';
不从Response
导入@angular/http
,Response
默认为ECMAScript API。