diff --git a/src/components/root/app-router.test.tsx b/src/components/root/app-router.test.tsx
index 4824ea7c8..8cc1fd715 100644
--- a/src/components/root/app-router.test.tsx
+++ b/src/components/root/app-router.test.tsx
@@ -2,8 +2,9 @@ import React from 'react';
import { render } from '../../test-utils';
import AppRouter from './app-router';
import rootReducer from '../../redux';
-import { createMockAppStore } from '../../setupTests';
+import { createMockAppStore, createParamInLocalStorage } from '../../setupTests';
import { screen } from '@testing-library/react';
+import rmgRuntime, { RmgEnv } from '@railmapgen/rmg-runtime';
jest.mock('./app-view', () => {
return () => (
@@ -27,36 +28,140 @@ const mockStore = createMockAppStore({
});
describe('AppRouter', () => {
- afterEach(() => {
- mockStore.clearActions();
- });
+ describe('AppRouter - UAT toggle on', () => {
+ beforeEach(() => {
+ jest.spyOn(rmgRuntime, 'getEnv').mockReturnValue(RmgEnv.UAT);
+ });
- it('Can render param selector view if param id is not specified', () => {
- render(, { store: mockStore, route: '/' });
+ afterEach(() => {
+ mockStore.clearActions();
+ });
- const actions = mockStore.getActions();
- expect(actions).toHaveLength(0);
+ it('Can render param selector view if param id is not specified', () => {
+ render(, { store: mockStore, route: '/' });
- expect(screen.getByRole('presentation', { name: 'Mock Param Selector View' })).toBeInTheDocument();
- });
+ const actions = mockStore.getActions();
+ expect(actions).toHaveLength(0);
+
+ expect(screen.getByRole('presentation', { name: 'Mock Param Selector View' })).toBeInTheDocument();
+ });
+
+ it('Can read param from localStorage and render app view if param is not loaded', () => {
+ createParamInLocalStorage('test-id');
+ render(, { store: mockStore, route: '/?project=test-id' });
+
+ const actions = mockStore.getActions();
+ expect(actions).toContainEqual({ type: 'app/setCurrentParamId', payload: 'test-id' });
+ expect(actions).toContainEqual(expect.objectContaining({ type: 'SET_FULL_PARAM' }));
+
+ expect(screen.getByRole('presentation', { name: 'Mock App View' })).toBeInTheDocument();
+ });
+
+ it('Can render param selector view if no param in localStorage matches URL param ID', () => {
+ render(, { store: mockStore, route: '/?project=test-id-2' });
- it('Can read param from localStorage and render app view if param is not loaded', () => {
- render(, { store: mockStore, route: '/?project=test-id' });
+ // TODO
+ // expect(screen.getByRole('presentation', { name: 'Mock Param Selector View' })).toBeInTheDocument();
+ });
- const actions = mockStore.getActions();
- expect(actions).toContainEqual({ type: 'app/setCurrentParamId', payload: 'test-id' });
- expect(actions).toContainEqual(expect.objectContaining({ type: 'SET_FULL_PARAM' }));
+ it('Can render app view if param is loaded', async () => {
+ const mockStore = createMockAppStore({
+ ...realStore,
+ app: { ...realStore.app, currentParamId: 'test-id' },
+ });
+ render(, { store: mockStore, route: '/?project=test-id' });
- expect(screen.getByRole('presentation', { name: 'Mock App View' })).toBeInTheDocument();
+ const actions = mockStore.getActions();
+ expect(actions).toHaveLength(0);
+
+ await screen.findByRole('presentation', { name: 'Mock App View' });
+ });
});
- it('Can render app view if param is loaded', async () => {
- const mockStore = createMockAppStore({ ...realStore, app: { ...realStore.app, currentParamId: 'test-id' } });
- render(, { store: mockStore, route: '/?project=test-id' });
+ describe('AppRouter - PRD toggle off', () => {
+ beforeEach(() => {
+ jest.spyOn(rmgRuntime, 'getEnv').mockReturnValue(RmgEnv.PRD);
+ });
+
+ afterEach(() => {
+ mockStore.clearActions();
+ window.localStorage.clear();
+ });
+
+ it('Can generate param and render app view if param id is not specified and no param in localStorage', () => {
+ render(, { store: mockStore, route: '/' });
+
+ // update redux store
+ const actions = mockStore.getActions();
+ expect(actions).toContainEqual(expect.objectContaining({ type: 'app/setCurrentParamId' }));
+ expect(actions).toContainEqual(expect.objectContaining({ type: 'SET_FULL_PARAM' }));
+
+ // route to new param id
+ const currentParamId = actions.find(action => action.type === 'app/setCurrentParamId').payload;
+ // TODO: URL search param?
+
+ expect(screen.getByRole('presentation', { name: 'Mock App View' })).toBeInTheDocument();
+ });
+
+ it('Can read first param from localStorage and render app view if param id is not specified', () => {
+ createParamInLocalStorage('test-id');
+ render(, { store: mockStore, route: '/' });
+
+ // update redux store
+ const actions = mockStore.getActions();
+ expect(actions).toContainEqual({ type: 'app/setCurrentParamId', payload: 'test-id' });
+ expect(actions).toContainEqual({
+ type: 'SET_FULL_PARAM',
+ fullParam: expect.objectContaining({ line_num: 'test-id' }),
+ });
+
+ // route to new param id
+ // TODO: URL search param?
+
+ expect(screen.getByRole('presentation', { name: 'Mock App View' })).toBeInTheDocument();
+ });
+
+ it('Can read param from localStorage and render app view if param is not loaded', () => {
+ createParamInLocalStorage('test-id');
+ render(, { store: mockStore, route: '/?project=test-id' });
+
+ const actions = mockStore.getActions();
+ expect(actions).toContainEqual({ type: 'app/setCurrentParamId', payload: 'test-id' });
+ expect(actions).toContainEqual(expect.objectContaining({ type: 'SET_FULL_PARAM' }));
+
+ // TODO: URL search param?
+
+ expect(screen.getByRole('presentation', { name: 'Mock App View' })).toBeInTheDocument();
+ });
+
+ it('Can read first param from localStorage and render app selector view if no param in localStorage matches URL param ID', () => {
+ createParamInLocalStorage('test-id-1');
+ render(, { store: mockStore, route: '/?project=test-id-2' });
+
+ // update redux store
+ const actions = mockStore.getActions();
+ expect(actions).toContainEqual({ type: 'app/setCurrentParamId', payload: 'test-id-1' });
+ expect(actions).toContainEqual({
+ type: 'SET_FULL_PARAM',
+ fullParam: expect.objectContaining({ line_num: 'test-id-1' }),
+ });
+
+ // TODO: URL search param?
+
+ expect(screen.getByRole('presentation', { name: 'Mock App View' })).toBeInTheDocument();
+ });
+
+ it('Can render app view if param is loaded', async () => {
+ const mockStore = createMockAppStore({
+ ...realStore,
+ app: { ...realStore.app, currentParamId: 'test-id' },
+ });
+ render(, { store: mockStore, route: '/?project=test-id' });
- const actions = mockStore.getActions();
- expect(actions).toHaveLength(0);
+ const actions = mockStore.getActions();
+ expect(actions).toHaveLength(0);
- await screen.findByRole('presentation', { name: 'Mock App View' });
+ await screen.findByRole('presentation', { name: 'Mock App View' });
+ });
});
});
diff --git a/src/components/root/app-router.tsx b/src/components/root/app-router.tsx
index a01ee29a5..82e343f01 100644
--- a/src/components/root/app-router.tsx
+++ b/src/components/root/app-router.tsx
@@ -2,16 +2,18 @@ import React, { useEffect, useState } from 'react';
import { useSearchParams } from 'react-router-dom';
import AppView from './app-view';
import { useRootDispatch, useRootSelector } from '../../redux';
-import rmgRuntime from '@railmapgen/rmg-runtime';
+import rmgRuntime, { RmgEnv } from '@railmapgen/rmg-runtime';
import { LanguageCode } from '@railmapgen/rmg-translate';
import ParamSelectorView from './param-selector-view';
import { readParam } from '../../redux/app/action';
+import { getParamMap } from '../../util/param-manager-utils';
+import { nanoid } from 'nanoid';
export default function AppRouter() {
const dispatch = useRootDispatch();
const { currentParamId } = useRootSelector(state => state.app);
- const [searchParams] = useSearchParams();
+ const [searchParams, setSearchParams] = useSearchParams();
const paramId = searchParams.get('project');
const [isLoaded, setIsLoaded] = useState(false);
@@ -20,16 +22,34 @@ export default function AppRouter() {
console.log('searchParam: project=' + paramId);
if (paramId) {
if (paramId === currentParamId) {
+ console.log('AppRouter:: Store param ID matches URL param ID. Rendering app view...');
setIsLoaded(true);
} else {
- console.warn(
- 'AppRouter:: URL param ID does not match store param ID. Reading param with ID=' + paramId
- );
+ if (rmgRuntime.getEnv() === RmgEnv.PRD) {
+ const paramMap = getParamMap();
+ const paramIds = Object.keys(paramMap);
+ if (paramIds.length && !paramIds.includes(paramId)) {
+ console.warn(
+ 'AppRouter:: URL param ID does not exist in localStorage. Reset to first param in localStorage in PRD env.'
+ );
+ const paramMap = getParamMap();
+ setSearchParams({ project: Object.keys(paramMap)[0] });
+ return;
+ }
+ }
+
+ console.log(`AppRouter:: Reading param (ID=${paramId}) from localStorage`);
dispatch(readParam(paramId, rmgRuntime.getLanguage() as LanguageCode));
setIsLoaded(true);
}
} else {
- console.log('AppRouter:: Render param selector');
+ if (rmgRuntime.getEnv() === RmgEnv.PRD) {
+ console.log('AppRouter:: Redirect to first param in localStorage in PRD env');
+ const paramMap = getParamMap();
+ setSearchParams({ project: Object.keys(paramMap)[0] ?? nanoid() });
+ } else {
+ console.log('AppRouter:: No URL param ID provided. Rendering param selector view...');
+ }
}
}, [paramId]);
diff --git a/src/components/root/param-selector-view.test.tsx b/src/components/root/param-selector-view.test.tsx
index cc3bb3034..9af8dc18e 100644
--- a/src/components/root/param-selector-view.test.tsx
+++ b/src/components/root/param-selector-view.test.tsx
@@ -2,25 +2,16 @@ import React from 'react';
import { render } from '../../test-utils';
import ParamSelectorView from './param-selector-view';
import rootReducer from '../../redux';
-import { createMockAppStore } from '../../setupTests';
-import { initParam } from '../../redux/param/util';
-import { LocalStorageKey, RmgStyle } from '../../constants/constants';
-import { LanguageCode } from '@railmapgen/rmg-translate';
+import { createMockAppStore, createParamInLocalStorage } from '../../setupTests';
import { fireEvent, screen } from '@testing-library/react';
const realStore = rootReducer.getState();
const mockStore = createMockAppStore({ ...realStore });
-const generateParamInLocalStorage = (id: string) => {
- const rmgParam = initParam(RmgStyle.MTR, LanguageCode.English);
- rmgParam.line_num = id;
- window.localStorage.setItem(LocalStorageKey.PARAM_BY_ID + id, JSON.stringify(rmgParam));
-};
-
describe('ParamSelectorView', () => {
it('Can render view with list of projects as expected', () => {
- generateParamInLocalStorage('test-1');
- generateParamInLocalStorage('test-2');
+ createParamInLocalStorage('test-1');
+ createParamInLocalStorage('test-2');
render(, { store: mockStore, route: '/' });
diff --git a/src/setupProxy.js b/src/setupProxy.js
index 922afb52a..9fb65fece 100644
--- a/src/setupProxy.js
+++ b/src/setupProxy.js
@@ -3,7 +3,7 @@ module.exports = app => {
res.send({
component: 'rmg',
version: '9.9.9',
- environment: 'DEV',
+ environment: 'PRD',
instance: 'localhost',
});
});
diff --git a/src/setupTests.ts b/src/setupTests.ts
index d38e341e1..e2d0bc420 100644
--- a/src/setupTests.ts
+++ b/src/setupTests.ts
@@ -1,7 +1,9 @@
import createMockStore from 'redux-mock-store';
-import { BranchStyle, StationDict } from './constants/constants';
+import { BranchStyle, LocalStorageKey, RmgStyle, StationDict } from './constants/constants';
import rootReducer, { RootState } from './redux';
import { getDefaultMiddleware, ThunkDispatch } from '@reduxjs/toolkit';
+import { initParam } from './redux/param/util';
+import { LanguageCode } from '@railmapgen/rmg-translate';
// FIXME: any -> AnyAction?
type DispatchExts = ThunkDispatch;
@@ -89,3 +91,9 @@ global.fetch = (...args) => {
return originalFetch(...args);
}
};
+
+export const createParamInLocalStorage = (id: string) => {
+ const rmgParam = initParam(RmgStyle.MTR, LanguageCode.English);
+ rmgParam.line_num = id;
+ window.localStorage.setItem(LocalStorageKey.PARAM_BY_ID + id, JSON.stringify(rmgParam));
+};