This commit is contained in:
bitCosi 2026-08-05 12:54:22 +07:00 committed by GitHub
commit f1ffa1a951
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 79 additions and 33 deletions

View file

@ -1,6 +1,7 @@
import { TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { HttpClient } from '@angular/common/http';
import { Router } from '@angular/router';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { OverlayContainer } from '@angular/cdk/overlay';
@ -25,7 +26,7 @@ import { API_END_POINTS, APICallStatusEnum, RTLActions, UI_MESSAGES } from '../s
import { RTLEffects } from './rtl.effects';
import { RTLState } from './rtl.state';
import { updateRootAPICallStatus, openSpinner, closeSpinner, openAlert, resetRootStore } from './rtl.actions';
import { updateRootAPICallStatus, openSpinner, closeSpinner, openAlert, resetRootStore, fetchRTLConfig, openSnackBar } from './rtl.actions';
import { resetLNDStore, fetchInfoLND, fetchPageSettings as fetchPageSettingsLND } from '../lnd/store/lnd.actions';
import { resetCLNStore } from '../cln/store/cln.actions';
import { resetECLStore } from '../eclair/store/ecl.actions';
@ -35,6 +36,7 @@ describe('RTL Root Effects', () => {
let effects: RTLEffects;
let mockStore: Store<RTLState>;
let snackBar: MatSnackBar;
let router: Router;
let container: any;
let httpClient: HttpClient;
let httpTestingController: HttpTestingController;
@ -62,6 +64,7 @@ describe('RTL Root Effects', () => {
effects = TestBed.inject(RTLEffects);
mockStore = TestBed.inject(Store);
snackBar = TestBed.inject(MatSnackBar);
router = TestBed.inject(Router);
httpClient = TestBed.inject(HttpClient);
httpTestingController = TestBed.inject(HttpTestingController);
container = document.createElement('div');
@ -125,6 +128,41 @@ describe('RTL Root Effects', () => {
});
});
it('should refresh application settings after default password login', () => {
const storeDispatchSpy = spyOn(mockStore, 'dispatch').and.callThrough();
const routerNavigateSpy = spyOn(router, 'navigate').and.stub();
effects.setLoggedInDetails(true, { token: 'test-token' });
expect(storeDispatchSpy.calls.all()[0].args[0]).toEqual(fetchRTLConfig());
expect(storeDispatchSpy.calls.all()[1].args[0]).toEqual(openSnackBar({ payload: 'Reset your password.' }));
expect(routerNavigateSpy).toHaveBeenCalledWith(['/settings/auth']);
});
it('should store application settings when selected node index is missing from config', (done) => {
const storeDispatchSpy = spyOn(mockStore, 'dispatch').and.callThrough();
actions = new ReplaySubject(1);
const appConfig = {
...mockRTLStoreState.root.appConfig,
SSO: { rtlSSO: 0, logoutRedirectLink: '/rtl/login' },
secret2FA: '',
allowPasswordUpdate: true,
selectedNodeIndex: 99
};
actions.next({ type: RTLActions.FETCH_APPLICATION_SETTINGS });
const sub = effects.appConfigFetch.subscribe((appConfigResponse) => {
expect(appConfigResponse).toEqual({ type: RTLActions.SET_APPLICATION_SETTINGS, payload: appConfig });
const setSelectedNodeAction = storeDispatchSpy.calls.all().find((call) => (call.args[0] as any).type === RTLActions.SET_SELECTED_NODE)?.args[0] as any;
expect(setSelectedNodeAction).toBeTruthy();
expect(setSelectedNodeAction.payload.currentLnNode.index).toEqual(appConfig.nodes[0].index);
done();
setTimeout(() => sub.unsubscribe());
});
const req = httpTestingController.expectOne(API_END_POINTS.CONF_API);
req.flush(appConfig);
expect(req.request.method).toEqual('GET');
});
it('should open snack bar', (done) => {
const snackBarOpenSpy = spyOn(snackBar, 'open').and.callThrough();
actions = new ReplaySubject(1);

View file

@ -4,7 +4,7 @@ import { Router } from '@angular/router';
import { Store } from '@ngrx/store';
import { Actions, createEffect, ofType } from '@ngrx/effects';
import { of, Subject } from 'rxjs';
import { map, mergeMap, catchError, take, withLatestFrom, takeUntil } from 'rxjs/operators';
import { map, mergeMap, switchMap, catchError, finalize, take, withLatestFrom, takeUntil } from 'rxjs/operators';
import { MatDialog } from '@angular/material/dialog';
import { MatSnackBar } from '@angular/material/snack-bar';
@ -198,7 +198,7 @@ export class RTLEffects implements OnDestroy {
appConfigFetch = createEffect(
() => this.actions.pipe(
ofType(RTLActions.FETCH_APPLICATION_SETTINGS),
mergeMap(() => {
switchMap(() => {
this.screenSize = this.commonService.getScreenSize();
if (this.screenSize === ScreenSizeEnum.XS || this.screenSize === ScreenSizeEnum.SM) {
this.alertWidth = '95%';
@ -212,34 +212,43 @@ export class RTLEffects implements OnDestroy {
}
this.store.dispatch(openSpinner({ payload: UI_MESSAGES.GET_RTL_CONFIG }));
this.store.dispatch(updateRootAPICallStatus({ payload: { action: 'FetchRTLConfig', status: APICallStatusEnum.INITIATED } }));
return this.httpClient.get<RTLConfiguration>(API_END_POINTS.CONF_API);
}),
map((rtlConfig: RTLConfiguration) => {
this.logger.info(rtlConfig);
this.store.dispatch(closeSpinner({ payload: UI_MESSAGES.GET_RTL_CONFIG }));
this.store.dispatch(updateRootAPICallStatus({ payload: { action: 'FetchRTLConfig', status: APICallStatusEnum.COMPLETED } }));
let searchNode: Node | null = null;
rtlConfig.nodes.forEach((node) => {
node.settings.currencyUnits = [...CURRENCY_UNITS, (node.settings?.currencyUnit ? node.settings?.currencyUnit : '')];
if (+(node.index || -1) === rtlConfig.selectedNodeIndex) {
searchNode = node;
}
});
if (searchNode) {
this.store.dispatch(setSelectedNode({ payload: { uiMessage: UI_MESSAGES.NO_SPINNER, prevLnNodeIndex: -1, currentLnNode: searchNode, isInitialSetup: true } }));
return {
type: RTLActions.SET_APPLICATION_SETTINGS,
payload: rtlConfig
};
} else {
return {
type: RTLActions.VOID
};
}
}),
catchError((err) => {
this.handleErrorWithAlert('FetchRTLConfig', UI_MESSAGES.GET_RTL_CONFIG, 'Fetch RTL Config Failed!', API_END_POINTS.CONF_API, err);
return of({ type: RTLActions.VOID });
let errorHandled = false;
return this.httpClient.get<RTLConfiguration>(API_END_POINTS.CONF_API).pipe(
map((rtlConfig: RTLConfiguration) => {
this.logger.info(rtlConfig);
this.store.dispatch(updateRootAPICallStatus({ payload: { action: 'FetchRTLConfig', status: APICallStatusEnum.COMPLETED } }));
let searchNode: Node | null = null;
const selectedNodeIndex = +rtlConfig.selectedNodeIndex;
rtlConfig.nodes?.forEach((node) => {
node.settings.currencyUnits = [...CURRENCY_UNITS, (node.settings?.currencyUnit ? node.settings?.currencyUnit : '')];
if ((node.index ?? -1) === selectedNodeIndex) {
searchNode = node;
}
});
searchNode = searchNode || rtlConfig.nodes?.[0] || null;
if (searchNode) {
this.store.dispatch(setSelectedNode({ payload: { uiMessage: UI_MESSAGES.NO_SPINNER, prevLnNodeIndex: -1, currentLnNode: searchNode, isInitialSetup: true } }));
return {
type: RTLActions.SET_APPLICATION_SETTINGS,
payload: rtlConfig
};
} else {
return {
type: RTLActions.VOID
};
}
}),
catchError((err) => {
errorHandled = true;
this.handleErrorWithAlert('FetchRTLConfig', UI_MESSAGES.GET_RTL_CONFIG, 'Fetch RTL Config Failed!', API_END_POINTS.CONF_API, err);
return of({ type: RTLActions.VOID });
}),
finalize(() => {
if (!errorHandled) {
this.store.dispatch(closeSpinner({ payload: UI_MESSAGES.GET_RTL_CONFIG }));
}
})
);
}))
);
@ -581,11 +590,10 @@ export class RTLEffects implements OnDestroy {
this.logger.info('Successfully Authorized!');
this.SetToken(postRes.token);
this.sessionService.setItem('defaultPassword', defaultPassword);
this.store.dispatch(fetchRTLConfig());
if (defaultPassword) {
this.store.dispatch(openSnackBar({ payload: 'Reset your password.' }));
this.router.navigate(['/settings/auth']);
} else {
this.store.dispatch(fetchRTLConfig());
}
}