Skip to content

Commit

Permalink
Merge branch 'main' into dst1957-replace-deprecated-color
Browse files Browse the repository at this point in the history
  • Loading branch information
ataker authored Aug 29, 2023
2 parents 3067607 + 89f8c78 commit c461263
Show file tree
Hide file tree
Showing 12 changed files with 1,464 additions and 23 deletions.
19 changes: 19 additions & 0 deletions src/applications/avs/api/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# AVS application

## Quick start to get running locally
Before you get started check [this page](https://depo-platform-documentation.scrollhelp.site/developer-docs/setting-up-your-local-frontend-environment) first to make sure you are setup to use the correct version of Node and Yarn.
- clone vets-website repo `git clone [email protected]:department-of-veterans-affairs/vets-website.git`
- navigate to the check-in application `cd src/applications/avs`
- run `yarn install`
- turn on local mocks `yarn --cwd $( git rev-parse --show-toplevel ) mock-api --responses src/applications/avs/api/mocks/index.js`
- start app `yarn --cwd $( git rev-parse --show-toplevel ) watch --env entry=avs`
- visit the app: `http://localhost:3001/my-health/care-notes/avs/64aee349ceec8352f2403cb0`

## Running tests
Unit tests for can be run using this command: `yarn test:unit --app-folder avs`. To get detailed errors, run this command with `--log-level=error`. To get coverage reports run this command `yarn test:unit --app-folder avs --coverage --coverage-html`. View the report at `/coverage/index.html`

Cypress tests can be run with the GUI using this command: `yarn cy:open`. From there you can filter by `avs` to run just AVS end to end tests.

Run Cypress from command line:
- Run all `yarn cy:run --spec "src/applications/avs/**/**/*"`
- Specify browser `-b electron`
20 changes: 20 additions & 0 deletions src/applications/avs/api/mocks/avs/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
const data = id => {
let avs = {};
const filename = `../../../tests/fixtures/${id}.json`;

try {
// eslint-disable-next-line import/no-dynamic-require
avs = require(filename);
} catch (e) {
// eslint-disable-next-line no-console
console.error(`Could not load file for AVS id ${id}.`);
}

return {
data: avs,
};
};

module.exports = {
data,
};
17 changes: 17 additions & 0 deletions src/applications/avs/api/mocks/feature-toggles/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
const generateFeatureToggles = (toggles = {}) => {
const { avsEnabled = true } = toggles;

return {
data: {
type: 'feature_toggles',
features: [
{
name: 'avs_enabled',
value: avsEnabled,
},
],
},
};
};

module.exports = { generateFeatureToggles };
21 changes: 21 additions & 0 deletions src/applications/avs/api/mocks/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/* eslint-disable camelcase */
const delay = require('mocker-api/lib/delay');

const commonResponses = require('../../../../platform/testing/local-dev-mock-api/common');

const featureToggles = require('./feature-toggles');
const avs = require('./avs');

const responses = {
...commonResponses,
'GET /v0/feature_toggles': featureToggles.generateFeatureToggles({}),
'GET /avs/v0/avs/:id': (req, res) => {
const { data } = avs.data(req.params.id);
if (!data.data) {
return res.status(404).json(data);
}
return res.json(data);
},
};

module.exports = delay(responses, 1000);
18 changes: 18 additions & 0 deletions src/applications/avs/api/v0.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { apiRequest } from '@department-of-veterans-affairs/platform-utilities/exports';
import environment from '@department-of-veterans-affairs/platform-utilities/environment';

const apiBasePath = `${environment.API_URL}/avs/v0`;

/**
* Get an AVS by ID
* @param {String} id
*
* @returns {Object} AVS
*/
export const getAvs = async id => {
return apiRequest(`${apiBasePath}/avs/${id}`, {
headers: {
'Content-Type': 'application/json',
},
});
};
15 changes: 0 additions & 15 deletions src/applications/avs/containers/App.jsx

This file was deleted.

79 changes: 79 additions & 0 deletions src/applications/avs/containers/Avs.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import React, { useEffect, useState } from 'react';
import { connect, useSelector } from 'react-redux';
import PropTypes from 'prop-types';

import FEATURE_FLAG_NAMES from '@department-of-veterans-affairs/platform-utilities/featureFlagNames';
import { selectUser } from '@department-of-veterans-affairs/platform-user/selectors';
import backendServices from '@department-of-veterans-affairs/platform-user/profile/backendServices';
import { RequiredLoginView } from '@department-of-veterans-affairs/platform-user/RequiredLoginView';

import { getAvs } from '../api/v0';

const Avs = props => {
const user = useSelector(selectUser);
const { avsEnabled, featureTogglesLoading } = useSelector(
state => {
return {
featureTogglesLoading: state.featureToggles.loading,
avsEnabled: state.featureToggles[FEATURE_FLAG_NAMES.avsEnabled],
};
},
state => state.featureToggles,
);
const { isLoggedIn } = props;
const { id } = props.params;

const [avs, setAvs] = useState({});
const [avsLoading, setAvsLoading] = useState(true);

useEffect(
() => {
const fetchAvs = async () => {
const response = await getAvs(id);
// cf. https://github.com/department-of-veterans-affairs/avs/blob/master/ll-avs-web/src/main/java/gov/va/med/lom/avs/client/model/AvsDataModel.java
setAvs(response.data.attributes);
setAvsLoading(false);
};

if (isLoggedIn && avsLoading) {
fetchAvs();
}
},
[avs, avsLoading, id, isLoggedIn],
);

if (avsEnabled === false) {
window.location.replace('/');
}

if (isLoggedIn && (avsLoading || featureTogglesLoading)) {
return (
<va-loading-indicator
data-testid="avs-loading-indicator"
message="Loading your After-visit Summary"
/>
);
}

return (
<div className="vads-l-grid-container main-content">
<RequiredLoginView
user={user}
serviceRequired={[backendServices.USER_PROFILE]}
>
<h1>After-visit Summary</h1>
</RequiredLoginView>
</div>
);
};

const mapStateToProps = state => ({
isLoggedIn: state.user.login.currentlyLoggedIn,
});

Avs.propTypes = {
isLoggedIn: PropTypes.bool,
params: PropTypes.object,
};

export default connect(mapStateToProps)(Avs);
7 changes: 4 additions & 3 deletions src/applications/avs/routes.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import React from 'react';
import { Route } from 'react-router';
import App from './containers/App';
import { Route } from 'react-router-dom';

const routes = <Route path="/" component={App} />;
import Avs from './containers/Avs';

const routes = [<Route path="/:id" key="/:id" component={Avs} />];

export default routes;
101 changes: 101 additions & 0 deletions src/applications/avs/tests/containers/Avs.unit.spec.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import React from 'react';
import { expect } from 'chai';
import { mockApiRequest } from '@department-of-veterans-affairs/platform-testing/helpers';
import { renderWithStoreAndRouter } from '@department-of-veterans-affairs/platform-testing/react-testing-library-helpers';
import { waitFor } from '@testing-library/react';
import backendServices from '@department-of-veterans-affairs/platform-user/profile/backendServices';
import sinon from 'sinon';
import Avs from '../../containers/Avs';

import mockAvs from '../fixtures/9A7AF40B2BC2471EA116891839113252.json';

describe('Avs container', () => {
let oldLocation;

beforeEach(() => {
oldLocation = global.window.location;
delete global.window.location;
global.window.location = {
replace: sinon.spy(),
};
});

afterEach(() => {
global.window.location = oldLocation;
});
const initialState = {
featureToggles: {
// eslint-disable-next-line camelcase
avs_enabled: false,
loading: false,
},
user: {
login: {
currentlyLoggedIn: false,
},
},
};
const props = {
params: {
id: 'foo',
},
};

it('user is not logged in', () => {
// expected behavior is be redirected to the home page with next in the url
renderWithStoreAndRouter(<Avs {...props} />, {
initialState,
});

expect(window.location.replace.called).to.be.true;
expect(window.location.replace.firstCall.args[0]).to.eq('/');
});

it('feature flags are still loading', () => {
const screen = renderWithStoreAndRouter(<Avs {...props} />, {
initialState: {
...initialState,
featureToggles: {
loading: true,
},
user: {
login: {
currentlyLoggedIn: true,
},
},
},
});
expect(screen.getByTestId('avs-loading-indicator'));
});

it('feature flag set to false', () => {
renderWithStoreAndRouter(<Avs {...props} />, { initialState });
expect(window.location.replace.called).to.be.true;
expect(window.location.replace.firstCall.args[0]).to.eq('/');
});

it('feature flag set to true', async () => {
mockApiRequest(mockAvs);
const screen = renderWithStoreAndRouter(<Avs {...props} />, {
initialState: {
...initialState,
featureToggles: {
// eslint-disable-next-line camelcase
avs_enabled: true,
loading: false,
},
user: {
login: {
currentlyLoggedIn: true,
},
profile: {
services: [backendServices.USER_PROFILE],
},
},
},
});
await waitFor(() => {
expect(screen.getByText('After-visit Summary'));
});
});
});
Loading

0 comments on commit c461263

Please sign in to comment.