Skip to content

Commit

Permalink
#40 Toggle off param selector view in PRD env
Browse files Browse the repository at this point in the history
  • Loading branch information
wongchito committed Nov 2, 2022
1 parent 5fd02d9 commit 8e4ea65
Show file tree
Hide file tree
Showing 5 changed files with 166 additions and 42 deletions.
149 changes: 127 additions & 22 deletions src/components/root/app-router.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 () => (
Expand All @@ -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(<AppRouter />, { 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(<AppRouter />, { 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(<AppRouter />, { 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(<AppRouter />, { store: mockStore, route: '/?project=test-id-2' });

it('Can read param from localStorage and render app view if param is not loaded', () => {
render(<AppRouter />, { 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(<AppRouter />, { 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(<AppRouter />, { 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(<AppRouter />, { 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(<AppRouter />, { 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(<AppRouter />, { 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(<AppRouter />, { 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(<AppRouter />, { 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' });
});
});
});
32 changes: 26 additions & 6 deletions src/components/root/app-router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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]);

Expand Down
15 changes: 3 additions & 12 deletions src/components/root/param-selector-view.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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(<ParamSelectorView />, { store: mockStore, route: '/' });

Expand Down
2 changes: 1 addition & 1 deletion src/setupProxy.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module.exports = app => {
res.send({
component: 'rmg',
version: '9.9.9',
environment: 'DEV',
environment: 'PRD',
instance: 'localhost',
});
});
Expand Down
10 changes: 9 additions & 1 deletion src/setupTests.ts
Original file line number Diff line number Diff line change
@@ -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<RootState, void, any>;
Expand Down Expand Up @@ -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));
};

0 comments on commit 8e4ea65

Please sign in to comment.