ohayolibs
Version:
Ohayo is a set of essential modules for ohayojp.
257 lines (239 loc) • 8.78 kB
text/typescript
import { DOCUMENT } from '@angular/common';
import { HttpClient, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse, HTTP_INTERCEPTORS } from '@angular/common/http';
import { HttpClientTestingModule, HttpTestingController, TestRequest } from '@angular/common/http/testing';
import { Type } from '@angular/core';
import { TestBed } from '@angular/core/testing';
import { Router } from '@angular/router';
import { RouterTestingModule } from '@angular/router/testing';
import { OhayoAuthConfig, OHAYO_CONFIG } from '@ohayo/util';
import { Observable, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';
import { OhayoAuthModule } from '../auth.module';
import { AuthReferrer, DA_SERVICE_TOKEN, ITokenModel, ITokenService } from './interface';
import { SimpleInterceptor } from './simple/simple.interceptor';
import { SimpleTokenModel } from './simple/simple.model';
function genModel<T extends ITokenModel>(modelType: new () => T, token: string | null = `123`): any {
const model: any = new modelType();
model.token = token;
model.uid = 1;
return model;
}
class MockTokenService implements ITokenService {
[key: string]: any;
_data: any;
options: any;
referrer: AuthReferrer = {};
refresh: Observable<ITokenModel>;
set(data: ITokenModel): boolean {
this._data = data;
return true;
}
get(): ITokenModel {
return this._data;
}
change(): any {
return null;
}
clear(): void {
this._data = null;
}
get login_url(): string {
return '/login';
}
}
let otherRes = new HttpResponse();
class OtherInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(req.clone()).pipe(
catchError(() => {
return throwError(otherRes);
}),
);
}
}
describe('auth: base.interceptor', () => {
let http: HttpClient;
let httpBed: HttpTestingController;
let router: Router;
const MockDoc = {
location: {
href: '',
},
};
function genModule(options: OhayoAuthConfig, tokenData?: ITokenModel, provider: any[] = []): void {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule, RouterTestingModule.withRoutes([]), OhayoAuthModule],
providers: [
{ provide: DOCUMENT, useValue: MockDoc },
{ provide: OHAYO_CONFIG, useValue: { auth: options } },
{
provide: HTTP_INTERCEPTORS,
useClass: SimpleInterceptor,
multi: true,
},
{ provide: DA_SERVICE_TOKEN, useClass: MockTokenService },
].concat(provider),
});
if (tokenData) TestBed.inject(DA_SERVICE_TOKEN).set(tokenData);
router = TestBed.inject<Router>(Router);
spyOn(router, 'navigate');
http = TestBed.inject<HttpClient>(HttpClient);
httpBed = TestBed.inject(HttpTestingController as Type<HttpTestingController>);
}
describe('[ignores]', () => {
describe('#with config', () => {
const basicModel = genModel(SimpleTokenModel);
it(`should be ignore /login`, done => {
genModule({ ignores: [/assets\//, /\/login/] }, basicModel);
http.get('/login', { responseType: 'text' }).subscribe(done);
const req = httpBed.expectOne('/login') as TestRequest;
expect(req.request.headers.get('token')).toBeNull();
req.flush('ok!');
});
it('should be empty ignore', done => {
genModule({ ignores: [] }, basicModel);
http.get('/login', { responseType: 'text' }).subscribe(done);
const req = httpBed.expectOne('/login') as TestRequest;
expect(req.request.headers.get('token')).toBe('123');
req.flush('ok!');
});
it('should be undefined', done => {
genModule({ ignores: undefined }, basicModel);
http.get('/login', { responseType: 'text' }).subscribe(done);
const req = httpBed.expectOne('/login') as TestRequest;
expect(req.request.headers.get('token')).toBe('123');
req.flush('ok!');
});
});
describe('#with allow_anonymous_key', () => {
describe('in params', () => {
it(`should working`, done => {
genModule({}, genModel(SimpleTokenModel, null));
http.get('/user', { responseType: 'text', params: { _allow_anonymous: '' } }).subscribe(done);
const ret = httpBed.expectOne(() => true);
expect(ret.request.params.has('_allow_anonymous')).toBe(false);
expect(ret.request.headers.get('Authorization')).toBeNull();
ret.flush('ok!');
});
it(`(full url)`, done => {
genModule({}, genModel(SimpleTokenModel, null));
http
.get('https://ohayojp.com/api/user', {
responseType: 'text',
params: { _allow_anonymous: '' },
})
.subscribe(done);
const ret = httpBed.expectOne(() => true);
expect(ret.request.headers.get('Authorization')).toBeNull();
ret.flush('ok!');
});
});
describe('in url', () => {
it(`should working`, done => {
genModule({}, genModel(SimpleTokenModel, null));
http.get('/user?_allow_anonymous=1', { responseType: 'text' }).subscribe(done);
const ret = httpBed.expectOne(() => true);
expect(ret.request.url).toBe(`/user`);
expect(ret.request.headers.get('Authorization')).toBeNull();
ret.flush('ok!');
});
it(`(full url)`, done => {
genModule({}, genModel(SimpleTokenModel, null));
http.get('https://ohayojp.com/api/user?a=1&_allow_anonymous=1&other=a&cn=中文', { responseType: 'text' }).subscribe(done);
const ret = httpBed.expectOne(() => true);
expect(ret.request.url).toBe(`https://ohayojp.com/api/user?a=1&other=a&cn=%E4%B8%AD%E6%96%87`);
expect(ret.request.headers.get('Authorization')).toBeNull();
ret.flush('ok!');
});
});
});
});
describe('[invalid token]', () => {
describe('should be navigate to login', () => {
it('with navigate', done => {
genModule({}, genModel(SimpleTokenModel, null));
http.get('/test', { responseType: 'text' }).subscribe(
() => {
expect(false).toBe(true);
done();
},
(err: any) => {
expect(err.status).toBe(401);
setTimeout(() => {
expect(TestBed.inject<Router>(Router).navigate).toHaveBeenCalled();
done();
}, 20);
},
);
});
it('with location', done => {
const login_url = 'https://ohayojp.com/login';
genModule({ login_url }, genModel(SimpleTokenModel, null));
http.get('/test', { responseType: 'text' }).subscribe(
() => {
expect(false).toBe(true);
done();
},
(err: any) => {
expect(err.status).toBe(401);
setTimeout(() => {
expect(TestBed.inject(DOCUMENT).location.href).toBe(login_url);
done();
}, 20);
},
);
});
});
it('should be not navigate to login when token_invalid_redirect: false', done => {
genModule({ token_invalid_redirect: false }, genModel(SimpleTokenModel, null));
http.get('/test', { responseType: 'text' }).subscribe(
() => {
expect(false).toBe(true);
done();
},
(err: any) => {
expect(err.status).toBe(401);
done();
},
);
});
});
describe('[referrer]', () => {
it('should be always router url', done => {
genModule({ executeOtherInterceptors: false }, genModel(SimpleTokenModel, null));
http.get('/to-test', { responseType: 'text' }).subscribe(
() => {
expect(false).toBe(true);
done();
},
() => {
const tokenSrv = TestBed.inject(DA_SERVICE_TOKEN) as MockTokenService;
expect(tokenSrv.referrer).not.toBeNull();
expect(tokenSrv.referrer.url).toBe('/');
done();
},
);
});
});
describe('[executeOtherInterceptors]', () => {
beforeEach(() => {
genModule({ executeOtherInterceptors: true }, genModel(SimpleTokenModel, null), [
{ provide: HTTP_INTERCEPTORS, useClass: OtherInterceptor, multi: true },
]);
});
it('shoul working', done => {
otherRes = new HttpResponse({ body: { a: 1 } });
const url = '/to-test?a=1';
http.get(url, { responseType: 'text' }).subscribe(
() => {
expect(false).toBe(true);
done();
},
err => {
expect(err.body.a).toBe(1);
done();
},
);
});
});
});