mirror of
https://gitlab.com/openstapps/openstapps.git
synced 2026-10-20 16:32:16 +00:00
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (C) 2026 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {TestBed} from '@angular/core/testing';
|
||||
import {HttpClient} from '@angular/common/http';
|
||||
import {BehaviorSubject, of} from 'rxjs';
|
||||
import {SCAssessment} from '@openstapps/core';
|
||||
import {AssessmentsProvider} from './assessments.provider';
|
||||
import {ConfigProvider} from '../config/config.provider';
|
||||
import {AuthActions, AuthProvider, IAuthAction} from '../auth/auth.provider';
|
||||
|
||||
class FakeAuth {
|
||||
events$ = new BehaviorSubject<IAuthAction>({action: AuthActions.Init});
|
||||
|
||||
accessToken = 'token-a';
|
||||
|
||||
getValidToken() {
|
||||
return Promise.resolve({accessToken: this.accessToken});
|
||||
}
|
||||
}
|
||||
|
||||
const gradesA = [{uid: 'a', name: 'Grade of A'}] as unknown as SCAssessment[];
|
||||
const gradesB = [{uid: 'b', name: 'Grade of B'}] as unknown as SCAssessment[];
|
||||
|
||||
describe('AssessmentsProvider', () => {
|
||||
let provider: AssessmentsProvider;
|
||||
let fakeAuth: FakeAuth;
|
||||
let httpClient: jasmine.SpyObj<HttpClient>;
|
||||
|
||||
beforeEach(() => {
|
||||
fakeAuth = new FakeAuth();
|
||||
httpClient = jasmine.createSpyObj<HttpClient>('HttpClient', ['get']);
|
||||
httpClient.get.and.callFake(((_url: string, options: {headers: {Authorization: string}}) =>
|
||||
of({data: options.headers.Authorization === 'Bearer token-a' ? gradesA : gradesB})) as never);
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
providers: [
|
||||
AssessmentsProvider,
|
||||
{
|
||||
provide: ConfigProvider,
|
||||
useValue: {config: {app: {features: {extern: {hisometry: {url: 'http://hisometry.local'}}}}}},
|
||||
},
|
||||
{provide: AuthProvider, useValue: fakeAuth},
|
||||
{provide: HttpClient, useValue: httpClient},
|
||||
],
|
||||
});
|
||||
|
||||
provider = TestBed.inject(AssessmentsProvider);
|
||||
});
|
||||
|
||||
it('should use the cache while the same user is logged in', async () => {
|
||||
await provider.getAssessments();
|
||||
fakeAuth.events$.next({action: AuthActions.RefreshSuccess});
|
||||
|
||||
expect(await provider.getAssessments()).toEqual(gradesA);
|
||||
expect(httpClient.get).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
for (const action of [AuthActions.SignOutSuccess, AuthActions.SessionExpired]) {
|
||||
it(`should clear the cache on ${action}`, async () => {
|
||||
await provider.getAssessments();
|
||||
fakeAuth.events$.next({action});
|
||||
|
||||
expect(provider.cache).toBeUndefined();
|
||||
expect(await provider.assessments).toEqual({});
|
||||
});
|
||||
}
|
||||
|
||||
it('should not show the grades of the previous user after a user change', async () => {
|
||||
expect(await provider.getAssessments()).toEqual(gradesA);
|
||||
|
||||
fakeAuth.events$.next({action: AuthActions.SignOutSuccess});
|
||||
fakeAuth.accessToken = 'token-b';
|
||||
fakeAuth.events$.next({action: AuthActions.SignInSuccess});
|
||||
|
||||
expect(await provider.getAssessments()).toEqual(gradesB);
|
||||
expect(httpClient.get).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
||||
@@ -17,7 +17,7 @@ import {ConfigProvider} from '../config/config.provider';
|
||||
import {SCAssessment, SCUuid} from '@openstapps/core';
|
||||
import {HttpClient} from '@angular/common/http';
|
||||
import {uniqBy, keyBy} from '@openstapps/collection-utils';
|
||||
import {AuthProvider} from '../auth/auth.provider';
|
||||
import {AuthActions, AuthProvider} from '../auth/auth.provider';
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -57,6 +57,24 @@ export class AssessmentsProvider {
|
||||
|
||||
readonly http = inject(HttpClient);
|
||||
|
||||
constructor() {
|
||||
/*
|
||||
* The grades belong to the logged-in user. The next user
|
||||
* should never get the previous user's grades from the cache.
|
||||
*/
|
||||
this.authProvider.events$.subscribe(({action}) => {
|
||||
switch (action) {
|
||||
case AuthActions.SignInSuccess:
|
||||
case AuthActions.SignOutSuccess:
|
||||
case AuthActions.SignOutFailed:
|
||||
case AuthActions.SessionExpired: {
|
||||
this.clearCache();
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
assessmentPath = 'assessments';
|
||||
|
||||
// usually this wouldn't be necessary, but the assessment service
|
||||
@@ -110,4 +128,13 @@ export class AssessmentsProvider {
|
||||
|
||||
return this.cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all cached grades.
|
||||
*/
|
||||
clearCache(): void {
|
||||
this.cache = undefined;
|
||||
this.assessments = Promise.resolve({});
|
||||
this.cacheTimestamp = 0;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user