Skip to content

Commit

Permalink
feat(mock): add mockInterceptor (#1698)
Browse files Browse the repository at this point in the history
  • Loading branch information
cipchk committed Nov 11, 2023
1 parent 4311426 commit da051b2
Show file tree
Hide file tree
Showing 14 changed files with 221 additions and 267 deletions.
2 changes: 1 addition & 1 deletion packages/auth/src/auth.config.ts
Expand Up @@ -9,7 +9,7 @@ export const AUTH_DEFAULT_CONFIG: AlainAuthConfig = {
token_send_place: 'header',
login_url: '/login',
ignores: [/\/login/, /assets\//, /passport\//],
executeOtherInterceptors: true,
executeOtherInterceptors: false,
refreshTime: 3000,
refreshOffset: 6000
};
Expand Down
6 changes: 3 additions & 3 deletions packages/mock/docs/getting-started.en-US.md
Expand Up @@ -35,7 +35,6 @@ Please refer to [global-config.module.ts](https://github.com/ng-alain/ng-alain/b
| `[delay]` | `number` | `300` | Request delay, unit is milliseconds ||
| `[force]` | `boolean` | `false` | Whether to force all requests to Mock, `true` means to return a 404 error directly when the requested URL does not exist, `false` means to send a real HTTP request when the request is missed ||
| `[log]` | `boolean` | `true` | Whether to print Mock request information, make up for the browser without Network information; it will output [👽Mock] when hit ||
| `[executeOtherInterceptors]` | `boolean` | `true` | Whether continue to call other interceptor `intercept` method after mock rule hit ||
| `[copy]` | `boolean` | `true` | Whether to return copy data ||

### Why is it only valid for development environment?
Expand All @@ -45,9 +44,10 @@ Mock is not real data, and most scenarios are for development local or test envi
Of course, you can also put the `provideDelonMockConfig` of `environment.ts` under `environment.prod.ts` so that the production environment also uses this rule, just like https://ng-alain.github.io/ng- Like alain/, some mock requests are needed to ensure the environment runs.

```ts
import { provideDelonMockConfig } from '@delon/mock';
import { mockInterceptor, provideDelonMockConfig } from '@delon/mock';
import * as MOCKDATA from '../../_mock';
export const environment = {
providers: [provideDelonMockConfig({ data: MOCKDATA })]
providers: [provideDelonMockConfig({ data: MOCKDATA })],
interceptorFns: [mockInterceptor],
} as Environment;
```
6 changes: 3 additions & 3 deletions packages/mock/docs/getting-started.zh-CN.md
Expand Up @@ -35,7 +35,6 @@ npm i --save-dev @delon/mock
| `[delay]` | `number` | `300` | 请求延迟,单位:毫秒 ||
| `[force]` | `boolean` | `false` | 是否强制所有请求都Mock,`true` 表示当请求的URL不存在时直接返回 404 错误,`false` 表示未命中时发送真实HTTP请求 ||
| `[log]` | `boolean` | `true` | 是否打印 Mock 请求信息,弥补浏览器无Network信息;当请求经过 Mock 会接收【👽Mock】 ||
| `[executeOtherInterceptors]` | `boolean` | `true` | 是否拦截命中后继续调用后续拦截器的 `intercept` 方法 ||
| `[copy]` | `boolean` | `true` | 是否返回副本数据 ||

### 为什么只对开发环境有效?
Expand All @@ -45,9 +44,10 @@ Mock 并非是真实数据,大部分场景是针对开发本地或测试环境
当然,也可以将 `environment.ts``provideDelonMockConfig` 放到 `environment.prod.ts` 下,使得生产环境也使用这种规则,就像 https://ng-alain.github.io/ng-alain/ 一样,需要一些模拟请求来保证环境的运行。

```ts
import { provideDelonMockConfig } from '@delon/mock';
import { mockInterceptor, provideDelonMockConfig } from '@delon/mock';
import * as MOCKDATA from '../../_mock';
export const environment = {
providers: [provideDelonMockConfig({ data: MOCKDATA })]
providers: [provideDelonMockConfig({ data: MOCKDATA })],
interceptorFns: [mockInterceptor],
} as Environment;
```
2 changes: 1 addition & 1 deletion packages/mock/src/mock.config.ts
Expand Up @@ -4,5 +4,5 @@ export const MOCK_DEFULAT_CONFIG: AlainMockConfig = {
delay: 300,
force: false,
log: true,
executeOtherInterceptors: true
executeOtherInterceptors: false
};
113 changes: 17 additions & 96 deletions packages/mock/src/mock.interceptor.spec.ts
@@ -1,26 +1,17 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import {
HttpClient,
HttpEvent,
HttpHandler,
HttpHeaders,
HttpInterceptor,
HttpRequest,
HttpResponse,
HTTP_INTERCEPTORS
} from '@angular/common/http';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import { Component, NgModule, Type } from '@angular/core';
import { fakeAsync, TestBed, tick } from '@angular/core/testing';
import { Router, RouterModule } from '@angular/router';
import { RouterTestingModule } from '@angular/router/testing';
import { Observable, lastValueFrom, map, of } from 'rxjs';
import { HttpClient, HttpHeaders, HttpResponse, provideHttpClient, withInterceptors } from '@angular/common/http';
import { HttpTestingController, provideHttpClientTesting } from '@angular/common/http/testing';
import { Component, Type } from '@angular/core';
import { TestBed } from '@angular/core/testing';
import { provideRouter } from '@angular/router';
import { lastValueFrom, of } from 'rxjs';

import * as Mock from 'mockjs';

import { AlainMockConfig, provideAlainConfig } from '@delon/util/config';

import { MockRequest } from './interface';
import { mockInterceptor } from './mock.interceptor';
import { provideDelonMockConfig } from './provide';
import { MockStatusError } from './status.error';
import { delay, r } from './utils';
Expand Down Expand Up @@ -51,38 +42,25 @@ const DATA = {
}
};

let otherRes = new HttpResponse();
class OtherInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(req.clone()).pipe(map(() => otherRes));
}
}

describe('mock: interceptor', () => {
let http: HttpClient;
let httpMock: HttpTestingController;

function genModule(
data: any,
options: AlainMockConfig,
imports: any[] = [],
spyConsole: boolean = true,
providers?: any[]
): void {
function genModule(data: any, options: AlainMockConfig, spyConsole: boolean = true): void {
TestBed.configureTestingModule({
declarations: [RootComponent],
imports: [
HttpClientTestingModule,
RouterTestingModule.withRoutes([
providers: [
provideHttpClient(withInterceptors([mockInterceptor])),
provideHttpClientTesting(),
provideRouter([
{
path: 'lazy',
loadChildren: jasmine.createSpy('expected')
}
])
].concat(imports),
providers: ([provideAlainConfig({ mock: options }), provideDelonMockConfig({ data })] as any[]).concat(
providers || []
)
]),
provideAlainConfig({ mock: options }),
provideDelonMockConfig({ data })
]
});
http = TestBed.inject<HttpClient>(HttpClient);
httpMock = TestBed.inject(HttpTestingController as Type<HttpTestingController>);
Expand All @@ -94,7 +72,7 @@ describe('mock: interceptor', () => {

describe('[default]', () => {
beforeEach(() => genModule(DATA, { executeOtherInterceptors: false, delay: 1 }));
it('should be init', (done: () => void) => {
it('should be init', done => {
http.get('/users').subscribe((res: any) => {
expect(res).not.toBeNull();
expect(res.users).not.toBeNull();
Expand Down Expand Up @@ -239,63 +217,6 @@ describe('mock: interceptor', () => {
});
});
});

describe('[lazy module]', () => {
beforeEach(() => genModule(DATA, { delay: 1 }));

it('should work', fakeAsync(() => {
@Component({
selector: 'lazy',
template: '<router-outlet></router-outlet>'
})
class LayoutComponent {}

@Component({
selector: 'child',
template: 'length-{{res.users.length}}'
})
class ChildComponent {
res: any = {};
constructor(HTTP: HttpClient) {
HTTP.get('/users').subscribe(res => (this.res = res));
}
}

@NgModule({
declarations: [LayoutComponent, ChildComponent],
imports: [RouterModule.forChild([{ path: 'child', component: ChildComponent }])],
providers: [provideDelonMockConfig()]
})
class LazyModule {}

const fixture = TestBed.createComponent(RootComponent);
fixture.detectChanges();

const router = TestBed.inject<Router>(Router);
router.resetConfig([{ path: 'lazy', loadChildren: () => LazyModule }]);
router.navigateByUrl(`/lazy/child`);
tick(500);
fixture.detectChanges();
const text = (fixture.nativeElement as HTMLElement).textContent;
expect(text).toContain('length-2');
}));
});
describe('[executeOtherInterceptors]', () => {
beforeEach(() => {
genModule(DATA, { delay: 1, executeOtherInterceptors: true }, [], true, [
{ provide: HTTP_INTERCEPTORS, useClass: OtherInterceptor, multi: true }
]);
});

it('should working', done => {
otherRes = new HttpResponse({ body: { a: 1 } });
http.get('/users').subscribe((res: any) => {
expect(res).not.toBeNull();
expect(res.a).toBe(1);
done();
});
});
});
});

@Component({
Expand Down

0 comments on commit da051b2

Please sign in to comment.