测试 Angular Effect + graphql apollo 客户端

Posted

技术标签:

【中文标题】测试 Angular Effect + graphql apollo 客户端【英文标题】:Testing Angular Effect + graphql apollo client 【发布时间】:2019-06-30 13:46:50 【问题描述】:

我正在尝试测试效果,但我不知道如何监视 watch 方法的 valueChanges 属性

@Effect()
signup$: Observable<Action> = this.actions$.pipe(
    ofType(AuthActionTypes.SIGNUP),
    map((action: Signup) => action.payload),
    switchMap((user: any) => 
        this.userSignup = user;
        return this.createUserGQL.mutate( userInput: user );
    ),
    switchMap(() => 
        return this.signInGQL.watch(
            email: this.userSignup.email,
            password: this.userSignup.password
        ).valueChanges.pipe(map((login: any) => 
            const authData = login.data.login;
            return authData;
        ));
    ),
    mergeMap((res: any) => 
        const token = res.token;
        this.localStorageService.setItem(AUTH_KEY,  token: token, isAuthenticated: true );
        return [ type: AuthActionTypes.SIGNUP_SUCCESS ,  type: AuthActionTypes.SET_TOKEN, payload: token ];
    ),
    catchError(err => 
        return of(new RetrieveError( error: err ));
    )
);

在我的规范文件中我有这个

describe('AuthEffects', () => 
let localStorageService: jasmine.SpyObj<LocalStorageService>;
let router: jasmine.SpyObj<Router>;
let createUserGQL: jasmine.SpyObj<CreateUserGQL>;
let signInGQL: jasmine.SpyObj<SignInGQL>;

beforeEach(() => 
    localStorageService = jasmine.createSpyObj('LocalStorageService', [
        'setItem'
    ]);
    router = jasmine.createSpyObj('Router', ['navigateByUrl']);
    createUserGQL = jasmine.createSpyObj('CreateUserGQL', ['mutate']);
    signInGQL = jasmine.createSpyObj('SignInGQL', ['watch']);
);

describe('signup', () => 
    it('should emit SignupSuccess and SetToken on success', () => 
        const userData: UserInputData =  name: 'test', email: 'test@test.com', password: 'secretsecret' ;
        const tokenData = 'tokensecretsecret';
        const mutationCreateUser = 
            id: '5c50364149012d0c8cf0fb37',
            name: 'test',
            email: 'test@test.com'
        ;
        const watchLogin = 
            token: '1234566787',
            userId: '5c50364149012d0c8cf0fb37'
        ;
        const signupAction = new Signup(userData);
        const expectedAction = [ type: AuthActionTypes.SIGNUP_SUCCESS ,  type: AuthActionTypes.SET_TOKEN, payload: tokenData ];
        const expectedValues = 
            b: expectedAction
        ;
        const source = cold('a',  a: signupAction );
        const expected = cold('b', expectedValues);
        const actions = new Actions(source);
        createUserGQL.mutate.and.returnValue(of(mutationCreateUser));
        signInGQL.watch.and.returnValue(of(watchLogin));
        const effect = new AuthEffects(actions, router, localStorageService, createUserGQL, signInGQL);
        expect(effect.signup$).toBeObservable(expected);

    );
);
);

但我有一个关于未定义的 .pipe 的错误,因为我没有 valueChanges 的 returnValue。

工作测试。需要传递一个带有propertyname: value的对象,而不是直接传递值。

@Effect()
signup$: Observable<Action> = this.actions$.pipe(
    ofType(AuthActionTypes.SIGNUP),
    map((action: Signup) => action.payload),
    switchMap((user: any) => 
        this.userSignup = user;
        return this.createUserGQL.mutate( userInput: user );
    ),
    switchMap(() => 
        return this.signInGQL.watch(
            email: this.userSignup.email,
            password: this.userSignup.password
        ).valueChanges.pipe(map((login: any) => 
            const authData = login.data.login;
            return authData;
        ));
    ),
    mergeMap((res: any) => 
        const token = res.token;
        this.localStorageService.setItem(AUTH_KEY,  token: token, isAuthenticated: true );
        return [new SignupSuccess, new SetToken(token)];
    ),
    catchError(err => 
        return of(new RetrieveError( error: err ));
    )
);



 describe('signup', () => 
    it('should emit SignupSuccess and SetToken on success', () => 
        const userData: UserInputData =  name: 'test', email: 'test@test.com', password: 'secretsecret' ;
        const tokenData = 'tokensecretsecret';
        const mutationCreateUser = 
            id: '5c50364149012d0c8cf0fb37',
            name: 'test',
            email: 'test@test.com'
        ;
        const watchLogin = 
            data: 
                login: 
                    token: '1234566787',
                    userId: '5c50364149012d0c8cf0fb37'
                
            
        ;
        const signupAction = new Signup(userData);
        const expectedValues = 
            b: new SignupSuccess,
            c: new SetToken(watchLogin.data.login.token)
        ;
        const source = cold('a',  a: signupAction );
        const expected = cold('(bc)', expectedValues);
        const actions = new Actions(source);
        createUserGQL.mutate.and.returnValue(of(mutationCreateUser));
        signInGQL.watch.and.returnValue(
            valueChanges: of(watchLogin)
        );
        const effect = new AuthEffects(actions, router, localStorageService, createUserGQL, signInGQL);
        expect(effect.signup$).toBeObservable(expected);
    );
);

【问题讨论】:

【参考方案1】:

试图帮助... 可能是缺少“valueChanges”属性的问题?

const signInGQL = jasmine.createSpyObj('SignInGQL', [ 'watch' ]);
signInGQL.watch.and.returnValue(
  valueChanges: of(watchLogin)  // instead of "of(watchLogin)"
);

【讨论】:

以上是关于测试 Angular Effect + graphql apollo 客户端的主要内容,如果未能解决你的问题,请参考以下文章

Angular 5 ngrx Effect 没有导出成员'ofType'

在ngrx/effect中访问存储的正确方法

关于 Angular 中的 Microsoft Graph API 集成 - Spring Boot 应用程序

如何在ngrx/effect(redux-observable)中调度多个动作?

@ngrx Effect 没有第二次运行

ngrx effect 多次调用observer,但只调度了一个action