diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000000..29e8410a25
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,15 @@
+#Ignore the following directories
+backend/build/
+backend/.gradle/
+frontend/build/
+frontend/node_modules/
+nginx/
+ops/**/.terraform/
+ops/services/app_functions/report_stream_batched_publisher/functions/node_modules/
+docs/
+.github/
+.run/
+node_modules/
+cypress/node_modules/
+cypress/screenshots/
+cypress/videos/
\ No newline at end of file
diff --git a/.env.cypress.sample b/.env.cypress.sample
index 96491aa828..395a1aad04 100644
--- a/.env.cypress.sample
+++ b/.env.cypress.sample
@@ -4,7 +4,7 @@ COMPOSE_HTTP_TIMEOUT=180
# Backend settings
SPRING_PROFILES_ACTIVE=e2e,db-dockerized
-WIREMOCK_URL=http://cypress:8088
+WIREMOCK_URL=http://wiremock:8088
SPRING_LIQUIBASE_ENABLED="true"
OKTA_TESTING_DISABLEHTTPSCHECK="true"
@@ -28,7 +28,7 @@ REACT_APP_BACKEND_URL=https://localhost.simplereport.gov/api
PUBLIC_URL=/app/
REACT_APP_OKTA_ENABLED=true
REACT_APP_DISABLE_MAINTENANCE_BANNER=true
-REACT_APP_OKTA_URL=http://cypress:8088
+REACT_APP_OKTA_URL=http://wiremock:8088
REACT_APP_BASE_URL=https://localhost.simplereport.gov
REACT_APP_OKTA_CLIENT_ID=
diff --git a/.github/workflows/buildBackendImage.yml b/.github/workflows/buildBackendImage.yml
index 02ebf4489b..39e1bc4176 100644
--- a/.github/workflows/buildBackendImage.yml
+++ b/.github/workflows/buildBackendImage.yml
@@ -60,7 +60,8 @@ jobs:
- name: Build and push Docker image
uses: docker/build-push-action@v4
with:
- context: backend
+ context: ./
+ file: ./backend/Dockerfile
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
diff --git a/.github/workflows/buildFrontendImage.yml b/.github/workflows/buildFrontendImage.yml
index 4742706d63..e73751162d 100644
--- a/.github/workflows/buildFrontendImage.yml
+++ b/.github/workflows/buildFrontendImage.yml
@@ -60,10 +60,19 @@ jobs:
- name: Build and push Docker image
uses: docker/build-push-action@v4
with:
- context: frontend
+ context: ./
+ file: ./frontend/Dockerfile
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
+ build-args: |
+ "REACT_APP_OKTA_URL=http://wiremock:8088"
+ "REACT_APP_OKTA_CLIENT_ID=0oa1k0163nAwfVxNW1d7"
+ "REACT_APP_BASE_URL=https://localhost.simplereport.gov"
+ "REACT_APP_BACKEND_URL=https://localhost.simplereport.gov/api"
+ "PUBLIC_URL=/app/"
+ "REACT_APP_OKTA_ENABLED=true"
+ "REACT_APP_DISABLE_MAINTENANCE_BANNER=true"
- name: Set version output
shell: bash
diff --git a/.github/workflows/buildFrontendLighthouseImage.yml b/.github/workflows/buildFrontendLighthouseImage.yml
new file mode 100644
index 0000000000..c111b60b1f
--- /dev/null
+++ b/.github/workflows/buildFrontendLighthouseImage.yml
@@ -0,0 +1,78 @@
+name: Build frontend docker image with okta disabled
+
+on:
+ workflow_dispatch:
+ workflow_call:
+ inputs:
+ force_build:
+ description: Force build
+ required: false
+ default: false
+ type: boolean
+ outputs:
+ version:
+ description: docker image version
+ value: ${{ jobs.build_and_push_frontend_image.outputs.version }}
+
+env:
+ REGISTRY: ghcr.io
+ IMAGE_NAME: ${{ github.repository }}/frontend-lighthouse
+
+jobs:
+
+ frontend_changes:
+ with:
+ what_to_check: frontend
+ uses: ./.github/workflows/checkForChanges.yml
+
+ build_and_push_frontend_image:
+ # We want to build the image if there are changes in the frontend folder, or if we are forcing a build, or if we are on the main branch
+ if: needs.frontend_changes.outputs.has_changes == 'true' || inputs.force_build == true || github.ref == 'refs/heads/main'
+ needs: [frontend_changes]
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ packages: write
+ outputs:
+ version: ${{ steps.set.outputs.version }}
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v3
+
+ - name: Log in to the Container registry
+ uses: docker/login-action@v2
+ with:
+ registry: ${{ env.REGISTRY }}
+ username: ${{ github.actor }}
+ password: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Extract metadata (tags, labels) for Docker
+ id: meta
+ uses: docker/metadata-action@v4
+ with:
+ images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
+ tags: |
+ type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', github.event.repository.default_branch) }}
+ type=ref,event=branch
+ type=ref,event=pr
+
+ - name: Build and push Docker image
+ uses: docker/build-push-action@v4
+ with:
+ context: ./
+ file: ./frontend/Dockerfile
+ push: true
+ tags: ${{ steps.meta.outputs.tags }}
+ labels: ${{ steps.meta.outputs.labels }}
+ build-args: |
+ "REACT_APP_BASE_URL=https://localhost.simplereport.gov"
+ "REACT_APP_BACKEND_URL=https://localhost.simplereport.gov/api"
+ "PUBLIC_URL=/app/"
+ "REACT_APP_OKTA_ENABLED=false"
+ "REACT_APP_DISABLE_MAINTENANCE_BANNER=true"
+
+ - name: Set version output
+ shell: bash
+ id: set
+ run: echo "version=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.version'] }}" >> "$GITHUB_OUTPUT"
diff --git a/.github/workflows/checkForChanges.yml b/.github/workflows/checkForChanges.yml
index 54a493a202..f56cdff91d 100644
--- a/.github/workflows/checkForChanges.yml
+++ b/.github/workflows/checkForChanges.yml
@@ -13,7 +13,7 @@ on:
value: ${{ jobs.check_for_changes.outputs.has_changes }}
jobs:
check_for_changes:
- runs-on: 'ubuntu-20.04'
+ runs-on: ubuntu-latest
outputs:
has_changes: ${{ steps.check_for_changes.outputs.has_changes }}
steps:
diff --git a/.github/workflows/e2eLocal.yml b/.github/workflows/e2eLocal.yml
index 53da666f9d..a2521ae1d7 100644
--- a/.github/workflows/e2eLocal.yml
+++ b/.github/workflows/e2eLocal.yml
@@ -50,22 +50,6 @@ jobs:
with:
swap-size-gb: 10
- - name: Generate certs
- run: |
- echo "::group::Generate ssl certs"
- sudo apt update
- sudo apt install libnss3-tools
- eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
- brew install mkcert
- mkcert -install
- mkdir -p certs
- cd certs
- mkcert localhost.simplereport.gov
- mv localhost.simplereport.gov.pem localhost.simplereport.gov.crt
- mv localhost.simplereport.gov-key.pem localhost.simplereport.gov.key
- cd ..
- echo "::endgroup::"
-
- name: Update files permissions
# Even though we don't use it, we need the .env file created here due to an issue similar to this one: https://github.com/mutagen-io/mutagen/issues/265
run: |
@@ -104,16 +88,17 @@ jobs:
SMARTY_AUTH_TOKEN: ${{ secrets.SMARTY_AUTH_TOKEN }}
SPRING_LIQUIBASE_ENABLED: "true"
GIT_DISCOVERY_ACROSS_FILESYSTEM: 1
+ WIREMOCK_URL: "http://wiremock:8088"
# cypress settings
+ CYPRESS_OKTA_REDIRECT_URI: "https%3A%2F%2Flocalhost.simplereport.gov%2Fapp"
CYPRESS_OKTA_USERNAME: ${{ secrets.CYPRESS_OKTA_USERNAME }}
CYPRESS_OKTA_PASSWORD: ${{ secrets.CYPRESS_OKTA_PASSWORD }}
CYPRESS_OKTA_SECRET: ${{ secrets.CYPRESS_OKTA_SECRET }}
CYPRESS_BACKEND_URL: "https://localhost.simplereport.gov/api"
- WIREMOCK_URL: "http://cypress:8088"
SPEC_PATH: "cypress/e2e/**"
TEST_ENV: "https://localhost.simplereport.gov"
# frontend settings
- REACT_APP_OKTA_URL: "http://cypress:8088"
+ REACT_APP_OKTA_URL: "http://wiremock:8088"
REACT_APP_OKTA_CLIENT_ID: 0oa1k0163nAwfVxNW1d7
REACT_APP_BASE_URL: https://localhost.simplereport.gov
REACT_APP_BACKEND_URL: https://localhost.simplereport.gov/api
@@ -135,12 +120,8 @@ jobs:
if: always()
shell: bash
run: |
- CONTAINERS=$(docker ps -a --format '{{.Names}}')
- for container in $CONTAINERS
- do
- echo "Saving $container logs"
- docker logs $container >& cypress/${container}.log
- done
+ echo "Saving $container logs"
+ docker compose -f docker-compose.yml -f docker-compose.cypress.yml logs --timestamps >& cypress-run.log
- name: Stop containers
if: always()
@@ -151,7 +132,7 @@ jobs:
echo "::endgroup::"
- name: Archive cypress failures
- if: failure()
+ if: always()
uses: actions/upload-artifact@v3
with:
name: cypress-results
@@ -164,4 +145,4 @@ jobs:
uses: actions/upload-artifact@v3
with:
name: logs
- path: cypress/*.log
+ path: cypress-run.log
diff --git a/.github/workflows/lighthouse.yml b/.github/workflows/lighthouse.yml
index 11d6c8ce94..5c8bd23db8 100644
--- a/.github/workflows/lighthouse.yml
+++ b/.github/workflows/lighthouse.yml
@@ -1,9 +1,19 @@
-name: "Run Lighthouse Audit"
+name: Run Lighthouse Audit
on:
- workflow_dispatch:
- pull_request:
- branches:
- - "**"
+ workflow_call:
+ inputs:
+ DOCKER_BACKEND_IMAGE_VERSION:
+ required: false
+ type: string
+ DOCKER_DATABASE_IMAGE_VERSION:
+ required: false
+ type: string
+ DOCKER_NGINX_IMAGE_VERSION:
+ required: false
+ type: string
+ DOCKER_FRONTEND_LIGHTHOUSE_IMAGE_VERSION:
+ required: false
+ type: string
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
@@ -23,22 +33,6 @@ jobs:
with:
swap-size-gb: 10
- - name: Generate certs
- run: |
- echo "::group::Generate ssl certs"
- sudo apt update
- sudo apt install libnss3-tools
- eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
- brew install mkcert
- mkcert -install
- mkdir -p certs
- cd certs
- mkcert localhost.simplereport.gov
- mv localhost.simplereport.gov.pem localhost.simplereport.gov.crt
- mv localhost.simplereport.gov-key.pem localhost.simplereport.gov.key
- cd ..
- echo "::endgroup::"
-
- name: Add hosts to /etc/hosts
run: |
sudo echo "127.0.0.1 localhost.simplereport.gov" | sudo tee -a /etc/hosts
@@ -66,11 +60,21 @@ jobs:
# docker settings
DOCKER_CLIENT_TIMEOUT: 180
COMPOSE_HTTP_TIMEOUT: 180
+ DOCKER_BACKEND_IMAGE_VERSION: ${{ inputs.DOCKER_BACKEND_IMAGE_VERSION }}
+ DOCKER_DATABASE_IMAGE_VERSION: ${{ inputs.DOCKER_DATABASE_IMAGE_VERSION }}
+ DOCKER_NGINX_IMAGE_VERSION: ${{ inputs.DOCKER_NGINX_IMAGE_VERSION }}
+ DOCKER_FRONTEND_LIGHTHOUSE_IMAGE_VERSION: ${{ inputs.DOCKER_FRONTEND_LIGHTHOUSE_IMAGE_VERSION }}
shell: bash
run: |
+ echo "::group::Running containers"
+ echo "Backend branch tag (or latest): ${{ inputs.DOCKER_BACKEND_IMAGE_VERSION }}"
+ echo "Database branch tag (or latest): ${{ inputs.DOCKER_DATABASE_IMAGE_VERSION }}"
+ echo "Nginx branch tag (or latest): ${{ inputs.DOCKER_NGINX_IMAGE_VERSION }}"
+ echo "Frontend branch tag (or latest): ${{ inputs.DOCKER_FRONTEND_LIGHTHOUSE_IMAGE_VERSION }}"
+ echo "::endgroup::"
+
echo "::group::Run Lighthouse locally"
- npm install -g @lhci/cli@0.9.x
- lhci autorun
+ bash lighthouse.sh
echo "::endgroup::"
- name: Archive Lighthouse results
diff --git a/.github/workflows/testingWorkflow.yml b/.github/workflows/testingWorkflow.yml
index 4c757f079d..8f376da504 100644
--- a/.github/workflows/testingWorkflow.yml
+++ b/.github/workflows/testingWorkflow.yml
@@ -23,6 +23,9 @@ jobs:
build_frontend_image:
uses: ./.github/workflows/buildFrontendImage.yml
+ build_frontend_lighthouse_image:
+ uses: ./.github/workflows/buildFrontendLighthouseImage.yml
+
build_nginx_image:
uses: ./.github/workflows/buildNginxImage.yml
@@ -47,7 +50,18 @@ jobs:
DOCKER_DATABASE_IMAGE_VERSION: ${{ needs.build_database_image.outputs.version }}
DOCKER_FRONTEND_IMAGE_VERSION: ${{ needs.build_frontend_image.outputs.version }}
DOCKER_NGINX_IMAGE_VERSION: ${{ needs.build_nginx_image.outputs.version }}
-
+ lighthouse:
+ needs:
+ - build_backend_image
+ - build_database_image
+ - build_nginx_image
+ - build_frontend_lighthouse_image
+ uses: ./.github/workflows/lighthouse.yml
+ with:
+ DOCKER_BACKEND_IMAGE_VERSION: ${{ needs.build_backend_image.outputs.version }}
+ DOCKER_FRONTEND_LIGHTHOUSE_IMAGE_VERSION: ${{ needs.build_frontend_lighthouse_image.outputs.version }}
+ DOCKER_DATABASE_IMAGE_VERSION: ${{ needs.build_database_image.outputs.version }}
+ DOCKER_NGINX_IMAGE_VERSION: ${{ needs.build_nginx_image.outputs.version }}
tests:
needs:
- build_database_image
diff --git a/.gitignore b/.gitignore
index 84ae3f2a94..79df860475 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,10 +9,10 @@ node_modules
*.orig
*.rej
/.env
+/.env.local
certs/
yarn-error.log
backend/locust/__pycache__/
-wiremock*.jar
cypress/cypress.env.json
frontend/src/.env.local
.run/Backend.run.xml
diff --git a/.run/e2e local headless.run.xml b/.run/e2e local headless.run.xml
new file mode 100644
index 0000000000..400a476e45
--- /dev/null
+++ b/.run/e2e local headless.run.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.run/e2e local open.run.xml b/.run/e2e local open.run.xml
new file mode 100644
index 0000000000..ac476df009
--- /dev/null
+++ b/.run/e2e local open.run.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/backend/Dockerfile b/backend/Dockerfile
index 911f9de7f3..e850170f47 100644
--- a/backend/Dockerfile
+++ b/backend/Dockerfile
@@ -1,18 +1,24 @@
-FROM gradle:7.6.1-jdk17
+FROM eclipse-temurin:17-jdk-alpine as build
LABEL org.opencontainers.image.source https://github.com/CDCgov/prime-simplereport
-WORKDIR /app/backend
+WORKDIR /app/
-# Only copy dependency-related files
-COPY build.gradle gradle.properties settings.gradle /app/backend/
+ADD ./backend /app/backend
+ADD ./.git /app/.git
-RUN chown -R gradle:gradle /app
-USER gradle
+# compile backend into a jar
+RUN cd backend && ./gradlew clean build -x test -x checkstyleMain -x spotlessCheck
-# Only download dependencies
-# Eat the expected build failure since no source code has been copied yet
-RUN gradle clean build --no-daemon > /dev/null 2>&1 || true
-CMD ["./run.sh"]
+FROM eclipse-temurin:17-jre-alpine
+LABEL org.opencontainers.image.source https://github.com/CDCgov/prime-simplereport
+
+RUN adduser -D appUser
+
+COPY --from=build /app/backend/build/libs/*.jar app.jar
+
+USER appUser
+
+ENTRYPOINT ["java","-jar","/app.jar"]
EXPOSE 8080
\ No newline at end of file
diff --git a/backend/src/main/java/gov/cdc/usds/simplereport/service/TestResultUploadService.java b/backend/src/main/java/gov/cdc/usds/simplereport/service/TestResultUploadService.java
index bf6f28bff9..2e4029db7a 100644
--- a/backend/src/main/java/gov/cdc/usds/simplereport/service/TestResultUploadService.java
+++ b/backend/src/main/java/gov/cdc/usds/simplereport/service/TestResultUploadService.java
@@ -171,7 +171,8 @@ private byte[] transformCsvContent(byte[] content) {
// row is passed by object reference here
modifyRowSpecimenNameToSNOMED(row, headers);
- modifyRowDatetimeStrings(row, headers);
+ // Disabling timezone conversion for now
+ // modifyRowDatetimeStrings(row, headers);
rows[i] = String.join(",", row);
}
diff --git a/backend/src/main/resources/application-e2e.yaml b/backend/src/main/resources/application-e2e.yaml
index 3f4675df66..ab98430f36 100644
--- a/backend/src/main/resources/application-e2e.yaml
+++ b/backend/src/main/resources/application-e2e.yaml
@@ -8,14 +8,29 @@ logging:
spring:
profiles:
include: server-debug, create-sample-devices
+ datasource:
+ simplereport:
+ hikari:
+ jdbc-url: jdbc:postgresql://db:${SR_DB_PORT:5432}/simple_report
+ metabase:
+ hikari:
+ jdbc-url: jdbc:postgresql://db:${SR_DB_PORT:5432}/metabase
liquibase:
simplereport:
user: simple_report_migrations
password: migrations456
+ hikari:
+ jdbc-url: jdbc:postgresql://db:5432/simple_report
+ maximum-pool-size: 50 # Maximum size that the pool is allowed to reach, including both idle and active connections. Effectively reflects number of concurrent database request threads. (Ex: A size of 50 represents a maximum capacity of 50 concurrent DB requests.)
+ max-lifetime: 600000 # Maximum lifetime for a connection to be retained in the pool, in milliseconds, once it is closed.
+ minimum-idle: 30
metabase:
user: simple_report_migrations
password: migrations456
default-schema: public
+ hikari:
+ maximum-pool-size: 2
+ jdbc-url: jdbc:postgresql://db:5432/metabase
jpa:
properties:
hibernate:
diff --git a/cypress/Dockerfile b/cypress/Dockerfile
index 606ea02147..1e65026f34 100644
--- a/cypress/Dockerfile
+++ b/cypress/Dockerfile
@@ -1,15 +1,6 @@
FROM cypress/browsers:node18.12.0-chrome107
LABEL org.opencontainers.image.source https://github.com/CDCgov/prime-simplereport
-RUN apt-get install -y wget apt-transport-https; \
- mkdir -p /etc/apt/keyrings; \
- wget -O - https://packages.adoptium.net/artifactory/api/gpg/key/public | tee /etc/apt/keyrings/adoptium.asc; \
- echo "deb [signed-by=/etc/apt/keyrings/adoptium.asc] https://packages.adoptium.net/artifactory/deb $(awk -F= '/^VERSION_CODENAME/{print$2}' /etc/os-release) main" | tee /etc/apt/sources.list.d/adoptium.list; \
- apt-get update; \
- apt-get upgrade; \
- apt-get install -y temurin-17-jdk; \
- apt-get install -y ant; \
- apt-get clean;
ADD ./cypress /app/cypress
RUN mkdir -p /app/cypress/screenshots
diff --git a/cypress/README.md b/cypress/README.md
index eae3fd663b..ab998f444c 100644
--- a/cypress/README.md
+++ b/cypress/README.md
@@ -18,7 +18,7 @@ COMPOSE_HTTP_TIMEOUT=180
# Backend settings
SPRING_PROFILES_ACTIVE=e2e,db-dockerized
-WIREMOCK_URL=http://cypress:8088
+WIREMOCK_URL=http://wiremock:8088
SPRING_LIQUIBASE_ENABLED="true"
OKTA_TESTING_DISABLEHTTPSCHECK="true"
@@ -41,7 +41,7 @@ REACT_APP_BACKEND_URL=https://localhost.simplereport.gov/api
PUBLIC_URL=/app/
REACT_APP_OKTA_ENABLED=true
REACT_APP_DISABLE_MAINTENANCE_BANNER=true
-REACT_APP_OKTA_URL=http://cypress:8088
+REACT_APP_OKTA_URL=http://wiremock:8088
REACT_APP_BASE_URL=https://localhost.simplereport.gov
REACT_APP_OKTA_CLIENT_ID=
diff --git a/cypress/cypress.config.js b/cypress/cypress.config.js
index 8060f9c623..80150ae4a8 100644
--- a/cypress/cypress.config.js
+++ b/cypress/cypress.config.js
@@ -1,21 +1,12 @@
-const {execSync, spawn} = require("child_process");
-const path = require("path");
-
-const isLocalRun = process.env["CYPRESS_IS_LOCAL_RUN"] || false;
-
-function getWiremockPath(filename) {
- let wiremockPath = isLocalRun ?
- "support/wiremock" : "cypress/support/wiremock";
- return `${wiremockPath}/${filename}`;
-}
module.exports = {
viewportWidth: 1200,
viewportHeight: 800,
defaultCommandTimeout: 10000,
video: true,
videoUploadOnPasses: false,
+ videoCompression: false,
retries: {
- runMode: 2,
+ runMode: 1,
openMode: 1,
},
e2e: {
@@ -30,6 +21,14 @@ module.exports = {
getAuth() {
return global.auth || {};
},
+ table(message) {
+ console.table(message);
+ return null;
+ },
+ print(message) {
+ console.log(message);
+ return null;
+ },
setPatientName: (name) => {
global.patientName = name;
return null;
@@ -71,43 +70,6 @@ module.exports = {
},
getMultiplexDeviceName() {
return global.multiplexDeviceName;
- },
- // These tasks are used to set up and run Wiremock
- downloadWiremock() {
- execSync(
- path.resolve(__dirname, getWiremockPath('download-wiremock.sh'))
- )
- return null;
- },
- startWiremock({ stubDir }) {
- const wm = spawn(
- path.resolve(__dirname, getWiremockPath('start-wiremock.sh')),
- [stubDir]
- );
- execSync(
- path.resolve(__dirname, getWiremockPath('ping-wiremock.sh')),
- );
- global.wm = wm;
- return null;
- },
- startOktaProxy() {
- const wm = spawn(
- path.resolve(__dirname, getWiremockPath('start-wiremock.sh')),
- );
- execSync(
- path.resolve(__dirname, getWiremockPath('ping-wiremock.sh')),
- );
- global.wm = wm;
- return null;
- },
- stopWiremock() {
- execSync(
- path.resolve(__dirname, getWiremockPath('stop-wiremock.sh')),
- );
- if (global.wm) {
- global.wm.kill();
- }
- return null;
}
})
on("before:browser:launch", (browser = {}, launchOptions = {}) => {
diff --git a/cypress/e2e.sh b/cypress/e2e.sh
index d8563c41e3..734b22afdf 100755
--- a/cypress/e2e.sh
+++ b/cypress/e2e.sh
@@ -76,18 +76,13 @@ echo
[[ -n $RUN_OPEN ]] && echo "Run as interactive-------$RUN_OPEN"
echo
-echo "Starting Wiremock for app bootup..."
-./cypress/support/wiremock/download-wiremock.sh >/dev/null 2>&1
-./cypress/support/wiremock/start-wiremock.sh orgSignUp >/dev/null 2>&1 &
-echo "Wiremock started!"
-echo
-echo "Waiting for backend to start at ${TEST_ENV}${BACKEND_URL_PATH}"
http_response=0
polls=0
-while [[ $http_response != "200" && $polls -lt 360 ]]; do
+while [[ $http_response != "200" && $polls -lt 72 ]]; do
((polls++))
- sleep 1
+ sleep 5
+ echo "Waiting for backend to start at ${TEST_ENV}${BACKEND_URL_PATH}"
http_response=$(curl -skL -w "%{http_code}" "${TEST_ENV}${BACKEND_URL_PATH}")
done
if [[ $http_response -ne 200 ]]; then
@@ -97,12 +92,12 @@ fi
echo 'Backend started!'
echo
-echo "Waiting for frontend to start at ${TEST_ENV}${PUBLIC_URL}${FRONTEND_URL_PATH}"
result=0
polls=0
-while [[ $result -ne 1 && $polls -lt 240 ]]; do
+while [[ $result -ne 1 && $polls -lt 48 ]]; do
((polls++))
- sleep 1
+ sleep 5
+ echo "Waiting for frontend to start at ${TEST_ENV}${PUBLIC_URL}${FRONTEND_URL_PATH}"
result=$(curl -skL "${TEST_ENV}${PUBLIC_URL}${FRONTEND_URL_PATH}" | grep -c '
SimpleReport')
done
if [[ $result -ne 1 ]]; then
diff --git a/cypress/e2e/00-health_check.cy.js b/cypress/e2e/00-health_check.cy.js
deleted file mode 100644
index e47fc27137..0000000000
--- a/cypress/e2e/00-health_check.cy.js
+++ /dev/null
@@ -1,6 +0,0 @@
-it("Checks if the frontend and backend are responding", () => {
- const commit_hash = Cypress.env("CHECK_COMMIT");
- const check_url = Cypress.env("CHECK_URL");
- cy.visit(check_url);
- cy.contains(commit_hash);
-});
diff --git a/cypress/e2e/01-organization_sign_up.cy.js b/cypress/e2e/01-organization_sign_up.cy.js
index 927e7ef83c..cad0d9df79 100644
--- a/cypress/e2e/01-organization_sign_up.cy.js
+++ b/cypress/e2e/01-organization_sign_up.cy.js
@@ -11,19 +11,10 @@ const user = generateUser();
describe("Organization sign up",() => {
loginHooks();
- before(() => {
- // Since these tests interact with Okta, we need to use
- // Wiremock to stub out the Okta API calls.
- cy.task("downloadWiremock");
- cy.restartWiremock("orgSignUp");
- });
- after(() => {
- cy.task("stopWiremock");
- });
it("navigates to the sign up form", () => {
cy.visit("/sign-up");
cy.injectSRAxe();
- cy.checkA11y(); // Sign up page
+ cy.checkAccessibility(); // Sign up page
cy.contains("Sign up for SimpleReport");
cy.contains("My organization is new to SimpleReport").click();
@@ -31,7 +22,7 @@ describe("Organization sign up",() => {
});
it("fills out the org info form", () => {
cy.contains("Sign up for SimpleReport in three steps");
- cy.checkA11y(); // Sign up form
+ cy.checkAccessibility(); // Sign up form
cy.get('input[name="name"]').type(organization.name);
cy.get('select[name="state"]').select("CA");
@@ -44,7 +35,7 @@ describe("Organization sign up",() => {
it("submits successfully", () => {
cy.get("button.submit-button").click();
cy.contains("Identity verification consent");
- cy.checkA11y(); // Identity verification page
+ cy.checkAccessibility(); // Identity verification page
});
it("navigates to the support pending org table and verifies the org", () => {
cy.removeOrganizationAccess();
@@ -53,13 +44,13 @@ describe("Organization sign up",() => {
cy.contains("Support admin");
cy.injectSRAxe();
- cy.checkA11y();
+ cy.checkAccessibility();
cy.contains("Identity verification").click();
cy.get("[data-cy=pending-orgs-title]").should("be.visible");
cy.contains("td", `${organization.name}`);
- cy.checkA11y();
+ cy.checkAccessibility();
cy.contains("td", `${organization.name}`)
.siblings()
@@ -82,7 +73,7 @@ describe("Organization sign up",() => {
cy.get('input[name="justification"]').type("I am a test user").blur();
cy.injectSRAxe();
- cy.checkA11y();
+ cy.checkAccessibility();
cy.contains("Access data").click();
cy.contains("Support admin");
@@ -96,13 +87,13 @@ describe("Organization sign up",() => {
// Test a11y on Manage Facilities tab
cy.injectSRAxe();
- cy.checkA11y();
+ cy.checkAccessibility();
cy.contains("+ New facility").click();
cy.contains("Testing facility information");
// Test a11y on New Facility page
- cy.checkA11y();
+ cy.checkAccessibility();
});
it("fills out the form for a new facility", () => {
cy.get('input[name="facility.name"]').type(facility.name);
@@ -120,7 +111,7 @@ describe("Organization sign up",() => {
'.modal__container input[name="addressSelect-facility"][value="userAddress"]+label'
).click();
- cy.checkA11y();
+ cy.checkAccessibility();
cy.get(".modal__container #save-confirmed-address").click();
cy.contains("+ New facility");
@@ -132,6 +123,6 @@ describe("Organization sign up",() => {
// Test a11y on the People page
cy.injectSRAxe();
- cy.checkA11y();
+ cy.checkAccessibility();
});
});
diff --git a/cypress/e2e/02-add_patient.cy.js b/cypress/e2e/02-add_patient.cy.js
index 9d2e02733f..df8d79d3b9 100644
--- a/cypress/e2e/02-add_patient.cy.js
+++ b/cypress/e2e/02-add_patient.cy.js
@@ -18,7 +18,7 @@ describe("Adding a single patient", () => {
cy.get("#individual_add-patient").click();
cy.get(".prime-edit-patient").contains("Add new patient");
cy.injectSRAxe();
- cy.checkA11y(); // Patient form
+ cy.checkAccessibility(); // Patient form
});
it("fills out some of the form fields", () => {
cy.get('input[name="firstName"]').type(patient.firstName);
@@ -53,7 +53,7 @@ it("fills out the remaining fields, submits and checks for the patient", () => {
'.modal__container input[name="addressSelect-person"][value="userAddress"]+label'
).click();
- cy.checkA11y();
+ cy.checkAccessibility();
cy.get(".modal__container #save-confirmed-address").click();
cy.get(".usa-card__header").contains("Patients");
@@ -61,6 +61,6 @@ it("fills out the remaining fields, submits and checks for the patient", () => {
cy.get("#search-field-small").type(patient.lastName);
cy.get(".prime-container").contains(patient.fullName);
- cy.checkA11y();
+ cy.checkAccessibility();
});
});
diff --git a/cypress/e2e/02b-bulk_upload_patient.cy.js b/cypress/e2e/02b-bulk_upload_patient.cy.js
index 16addd371f..ce0979a268 100644
--- a/cypress/e2e/02b-bulk_upload_patient.cy.js
+++ b/cypress/e2e/02b-bulk_upload_patient.cy.js
@@ -17,7 +17,7 @@ describe("Bulk upload patients", () => {
cy.get("#upload_add-patient").click();
cy.get(".prime-edit-patient").contains("Set up your spreadsheet");
cy.injectSRAxe();
- cy.checkA11y(); // Bulk upload patient form
+ cy.checkAccessibility(); // Bulk upload patient form
});
it("uploads csv file of patients", () => {
const csvFileContent = "last_name,first_name,middle_name,suffix,race,date_of_birth,biological_sex,ethnicity,street,street2,city,county,state,zip_code,country,phone_number,phone_number_type,employed_in_healthcare,resident_congregate_setting,role,email\n"
diff --git a/cypress/e2e/03-add_devices.cy.js b/cypress/e2e/03-add_devices.cy.js
index 933df467f0..0e00995f13 100644
--- a/cypress/e2e/03-add_devices.cy.js
+++ b/cypress/e2e/03-add_devices.cy.js
@@ -28,7 +28,7 @@ describe("Adding covid only and multiplex devices", () => {
cy.contains("Device type");
cy.contains("Save changes").should("be.not.enabled");
cy.injectSRAxe();
- cy.checkA11y();
+ cy.checkAccessibility();
cy.addDevice(covidOnlyDevice);
});
@@ -51,7 +51,7 @@ describe("Adding covid only and multiplex devices", () => {
.click();
cy.get('input[name="name"]').should("have.value", multiplexDevice.name);
cy.injectSRAxe();
- cy.checkA11y();
+ cy.checkAccessibility();
cy.get('input[name="model"]').should("have.value", multiplexDevice.model);
cy.get('input[name="manufacturer"]').should("have.value", multiplexDevice.manufacturer);
cy.get(".pill").should("have.length", 1);
@@ -84,7 +84,7 @@ describe("Adding covid only and multiplex devices", () => {
cy.wait("@GetFacilities");
cy.contains("Manage devices");
cy.injectSRAxe();
- cy.checkA11y();
+ cy.checkAccessibility();
cy.get('input[role="combobox"]').first().type(covidOnlyDevice.name);
cy.get('li[id="multi-select-deviceTypes-list--option-0"]').click();
cy.get('input[role="combobox"]').first().type(multiplexDevice.name);
diff --git a/cypress/e2e/04-conduct_test.cy.js b/cypress/e2e/04-conduct_test.cy.js
index c19fb7c1dc..f3198dc99c 100644
--- a/cypress/e2e/04-conduct_test.cy.js
+++ b/cypress/e2e/04-conduct_test.cy.js
@@ -33,7 +33,7 @@ describe("Conducting a COVID test", () => {
cy.wait("@GetPatientsByFacilityForQueue")
cy.injectSRAxe();
- cy.checkA11y(); // Conduct Tests page
+ cy.checkAccessibility(); // Conduct Tests page
});
it("begins a test", () => {
cy.get(".results-dropdown").within(() => {
@@ -47,7 +47,7 @@ describe("Conducting a COVID test", () => {
);
// Test a11y on the AoE modal
- cy.checkA11y();
+ cy.checkAccessibility();
});
it("fills out the aoe questions and submits", () => {
cy.get(".ReactModal__Content").within(() => {
@@ -63,7 +63,7 @@ describe("Conducting a COVID test", () => {
cy.get(queueCard).contains("COVID-19 results");
- cy.checkA11y(); // Test Card page
+ cy.checkAccessibility(); // Test Card page
});
it("completes the test", () => {
cy.get(queueCard).within(() => {
@@ -77,13 +77,13 @@ describe("Conducting a COVID test", () => {
cy.wait("@GetFacilityQueue", {timeout: 20000});
cy.get(queueCard).within(() => {
- cy.get('.prime-radios input[value="NEGATIVE"]+label').click();
+ cy.get('[data-cy="radio-group-option-NEGATIVE"]').click()
});
cy.wait("@EditQueueItem");
cy.get(queueCard).within(() => {
- cy.get(".prime-test-result-submit button").last().click();
+ cy.get(".prime-test-result-submit button").last().should("be.enabled").click();
});
cy.wait("@SubmitQueueItem");
@@ -96,7 +96,7 @@ describe("Conducting a COVID test", () => {
cy.get(".usa-table").contains(patientName);
// Test a11y on the Results page
- cy.checkA11y();
+ cy.checkAccessibility();
});
it("stores the patient link", () => {
cy.get(".sr-test-result-row").then(($row) => {
diff --git a/cypress/e2e/05-get_result_from_patient_link.cy.js b/cypress/e2e/05-get_result_from_patient_link.cy.js
index 4535e466ae..4ebd46eb7f 100644
--- a/cypress/e2e/05-get_result_from_patient_link.cy.js
+++ b/cypress/e2e/05-get_result_from_patient_link.cy.js
@@ -19,7 +19,7 @@ describe("Getting a test result from a patient link", () => {
});
it("contains no accessibility issues", () => {
cy.injectSRAxe();
- cy.checkA11y(); // PXP page
+ cy.checkAccessibility(); // PXP page
});
it("accepts the terms of service", () => {
cy.contains("Terms of service");
@@ -39,7 +39,7 @@ describe("Getting a test result from a patient link", () => {
const birthDay = dob.date();
const birthYear = dob.year();
- cy.checkA11y(); // DoB entry page
+ cy.checkAccessibility(); // DoB entry page
cy.get('input[name="month"]').type(birthMonth);
cy.get('input[name="day"]').type(birthDay);
@@ -52,6 +52,6 @@ describe("Getting a test result from a patient link", () => {
cy.contains("Test date");
cy.contains("Test device");
- cy.checkA11y(); // Result page
+ cy.checkAccessibility(); // Result page
});
});
diff --git a/cypress/e2e/06-self_registration.cy.js b/cypress/e2e/06-self_registration.cy.js
index f474004df5..79782e69be 100644
--- a/cypress/e2e/06-self_registration.cy.js
+++ b/cypress/e2e/06-self_registration.cy.js
@@ -12,7 +12,7 @@ describe("Patient self registration", () => {
// Test a11y on the Patient self registration page
cy.injectSRAxe();
- cy.checkA11y();
+ cy.checkAccessibility();
cy.get("#org-link").then(($link) => cy.visit($link.val()));
});
@@ -20,13 +20,13 @@ describe("Patient self registration", () => {
cy.contains("Terms of service");
cy.injectSRAxe();
- cy.checkA11y(); // Terms of Service
+ cy.checkAccessibility(); // Terms of Service
});
it("accepts the terms of service", () => {
cy.contains("I agree").click();
cy.get("#registration-container").contains("General information");
- cy.checkA11y(); // Info form
+ cy.checkAccessibility(); // Info form
});
it("fills out some of the form fields", () => {
cy.get('input[name="firstName"]').type(patient.firstName);
@@ -59,13 +59,13 @@ describe("Patient self registration", () => {
'.modal__container input[name="addressSelect-person"][value="userAddress"]+label'
).scrollIntoView().click();
- cy.checkA11y();
+ cy.checkAccessibility();
cy.get(".modal__container #save-confirmed-address").click();
cy.get("#self-reg-confirmation").contains(
"thanks for completing your patient profile"
);
- cy.checkA11y(); // Confirmation page
+ cy.checkAccessibility(); // Confirmation page
});
});
diff --git a/cypress/e2e/07-organization_settings.cy.js b/cypress/e2e/07-organization_settings.cy.js
index 0f8d6a175a..c8ad8a1598 100644
--- a/cypress/e2e/07-organization_settings.cy.js
+++ b/cypress/e2e/07-organization_settings.cy.js
@@ -17,18 +17,20 @@ describe("Updating organization settings", () => {
// Test a11y on the Manage organization page
cy.injectSRAxe();
- cy.checkA11y();
+ cy.checkAccessibility();
});
it("attempts an empty selection for organization type", () => {
+ cy.get('select[name="type"]').find('option:selected').should('have.text','Camp');
cy.get('select[name="type"]').select("- Select -");
- cy.contains("Save settings").click();
+ cy.contains("Save settings").should("be.enabled").click();
});
it("displays a validation toast", () => {
cy.contains("An organization type must be selected");
});
it("attempts a valid selection for organization type", () => {
cy.get('select[name="type"]').select("Nursing home");
- cy.contains("Save settings").click();
+ cy.contains("Save settings").should("be.enabled").click();
+ cy.wait("@AdminSetOrganization")
});
it("displays a success toast", () => {
cy.get(".Toastify").contains("Updated organization");
diff --git a/cypress/e2e/08-account_creation.cy.js b/cypress/e2e/08-account_creation.cy.js
index f72a273643..5340684075 100644
--- a/cypress/e2e/08-account_creation.cy.js
+++ b/cypress/e2e/08-account_creation.cy.js
@@ -16,7 +16,7 @@ Cypress.Commands.add("setPassword", () => {
cy.get('input[name="confirm-password"]').type(pass);
cy.get(submitButton).click();
cy.contains("Select your security question");
- cy.checkA11y();
+ cy.checkAccessibility();
});
Cypress.Commands.add("setSecurityQuestion", () => {
@@ -26,7 +26,7 @@ Cypress.Commands.add("setSecurityQuestion", () => {
cy.get('input[name="answer"]').type("Jane Doe");
cy.get(submitButton).click();
cy.contains("Set up authentication");
- cy.checkA11y();
+ cy.checkAccessibility();
});
Cypress.Commands.add("mfaSelect", (choice) => {
@@ -39,7 +39,7 @@ Cypress.Commands.add("mfaSelect", (choice) => {
Cypress.Commands.add("enterPhoneNumber", () => {
cy.contains("Get your security code via");
- cy.checkA11y();
+ cy.checkAccessibility();
cy.get('input[name="phone-number"]').type("530867530");
cy.contains("Get your security code via").click();
cy.contains("Enter a valid phone number");
@@ -50,41 +50,34 @@ Cypress.Commands.add("enterPhoneNumber", () => {
Cypress.Commands.add("scanQrCode", () => {
cy.contains("Get your security code via");
- cy.checkA11y();
+ cy.checkAccessibility();
cy.get(submitButton).click();
});
Cypress.Commands.add("verifySecurityCode", (code) => {
cy.contains("Verify your security code.");
cy.contains('One-time security code');
- cy.checkA11y();
+ cy.checkAccessibility();
cy.get('input[name="security-code"]').type(code);
cy.get(submitButton).first().click();
});
describe("Okta account creation", () => {
- // Since these tests interact with Okta, we need to use
- // Wiremock to stub out the Okta API calls.
- before(() => {
- cy.clearCookies();
- cy.task("downloadWiremock");
- cy.restartWiremock("accountCreation");
- });
beforeEach(() => {
// Cypress clears cookies by default, but for these tests
// we want to preserve the Spring session cookie
Cypress.Cookies.preserveOnce("SESSION");
});
- after(() => {
- cy.clearCookies();
- cy.task("stopWiremock");
- });
describe("Account creation w/ SMS MFA", () => {
+ before(() => {
+ cy.clearCookies();
+ cy.resetWiremock();
+ });
it("navigates to the activation link", () => {
cy.visit("/uac/?activationToken=h971awbXda7y7jGaxN8f");
cy.contains("Create your password");
cy.injectSRAxe();
- cy.checkA11y();
+ cy.checkAccessibility();
});
it("sets a password", () => {
cy.setPassword();
@@ -103,13 +96,14 @@ describe("Okta account creation", () => {
});
it("displays a success message", () => {
cy.contains("Account set up complete");
- cy.checkA11y();
+ cy.checkAccessibility();
});
});
describe("Account creation w/ Okta Verify MFA", () => {
before(() => {
- cy.restartWiremock("accountCreation");
+ cy.clearCookies();
+ cy.resetWiremock();
});
it("navigates to the activation link", () => {
cy.visit("/uac/?activationToken=NOr20VqF5M6m8AnwcSUJ");
@@ -133,13 +127,15 @@ describe("Okta account creation", () => {
});
it("displays a success message", () => {
cy.contains("Account set up complete");
- cy.checkA11y();
+ cy.checkAccessibility();
});
});
describe("Account creation w/ Google Authenticator MFA", () => {
before(() => {
- cy.restartWiremock("accountCreation");
+ cy.clearCookies();
+ cy.resetWiremock();
+
});
it("navigates to the activation link", () => {
cy.visit("/uac/?activationToken=gqYPzH1FlPzVr0U3tQ7H");
@@ -163,13 +159,14 @@ describe("Okta account creation", () => {
});
it("displays a success message", () => {
cy.contains("Account set up complete");
- cy.checkA11y();
+ cy.checkAccessibility();
});
});
describe("Account creation w/ Voice Call MFA", () => {
before(() => {
- cy.restartWiremock("accountCreation");
+ cy.clearCookies();
+ cy.resetWiremock();
});
it("navigates to the activation link", () => {
cy.visit("/uac/?activationToken=wN5mR-8SXao1TP2PLaFe");
@@ -193,13 +190,14 @@ describe("Okta account creation", () => {
});
it("displays a success message", () => {
cy.contains("Account set up complete");
- cy.checkA11y();
+ cy.checkAccessibility();
});
});
describe("Account creation w/ Email MFA", () => {
before(() => {
- cy.restartWiremock("accountCreation");
+ cy.clearCookies();
+ cy.resetWiremock();
});
it("navigates to the activation link", () => {
cy.visit("/uac/?activationToken=4OVwdVhc6M1I-UwvLrNX");
@@ -220,7 +218,7 @@ describe("Okta account creation", () => {
});
it("displays a success message", () => {
cy.contains("Account set up complete");
- cy.checkA11y();
+ cy.checkAccessibility();
});
});
});
diff --git a/cypress/e2e/09-multiplex_testing.cy.js b/cypress/e2e/09-multiplex_testing.cy.js
index 3da00ab611..ff870a3a9e 100644
--- a/cypress/e2e/09-multiplex_testing.cy.js
+++ b/cypress/e2e/09-multiplex_testing.cy.js
@@ -62,7 +62,7 @@ describe("Testing with multiplex devices", () => {
cy.contains(`${patient.lastName}, ${patient.firstName}`);
cy.injectSRAxe();
- cy.checkA11y();
+ cy.checkAccessibility();
const queueCard = `div[data-testid="test-card-${patient.internalId}"]`;
cy.get(queueCard).within(() => {
@@ -95,7 +95,6 @@ describe("Testing with multiplex devices", () => {
cy.get(queueCard).within(() => {
cy.get("@submitBtn").should("be.enabled").click();
});
-
cy.contains("Submit anyway").click();
cy.wait("@SubmitQueueItem");
cy.wait("@GetFacilityQueue", {timeout: 20000});
diff --git a/cypress/e2e/10-save_and_start_covid_test.cy.js b/cypress/e2e/10-save_and_start_covid_test.cy.js
index 99a1c84c13..23cd3bbb5c 100644
--- a/cypress/e2e/10-save_and_start_covid_test.cy.js
+++ b/cypress/e2e/10-save_and_start_covid_test.cy.js
@@ -42,7 +42,7 @@ describe('Save and start covid test',()=>{
cy.contains("General information").should('exist');
// a11y scan of edit patient page
cy.injectSRAxe();
- cy.checkA11y();
+ cy.checkAccessibility();
cy.get('input[name="middleName"]').clear().type(testNumber().toString(10));
cy.get(".prime-save-patient-changes-start-test").click();
});
@@ -67,7 +67,7 @@ describe('Save and start covid test',()=>{
cy.contains("New loss of taste").should('exist').click();
// Test a11y on the AoE form
- cy.checkA11y();
+ cy.checkAccessibility();
cy.contains("button", "Continue").click();
cy.get(".prime-home").contains(patientName);
@@ -76,7 +76,7 @@ describe('Save and start covid test',()=>{
cy.wait("@GetFacilityQueue", {timeout: 20000});
// Test a11y on the Test Queue page
- cy.checkA11y();
+ cy.checkAccessibility();
});
});
@@ -93,7 +93,7 @@ describe('Save and start covid test',()=>{
cy.get(".prime-edit-patient").contains("Add new patient");
cy.injectSRAxe();
- cy.checkA11y(); // New Patient page
+ cy.checkAccessibility(); // New Patient page
});
it("fills out form fields and clicks save and start test and verifies AoE form is correctly filled in", () => {
@@ -116,7 +116,7 @@ describe('Save and start covid test',()=>{
'.modal__container input[name="addressSelect-person"][value="userAddress"]+label'
).click();
- cy.checkA11y();
+ cy.checkAccessibility();
cy.get(".modal__container #save-confirmed-address").click();
cy.url().should("include", "queue");
diff --git a/cypress/package.json b/cypress/package.json
index 47c6b93dcb..80494747c3 100644
--- a/cypress/package.json
+++ b/cypress/package.json
@@ -11,7 +11,8 @@
"otplib": "^12.0.1"
},
"scripts": {
- "e2e:local": "env $(cat ./../.env | grep -v \"#\" | xargs) CYPRESS_IS_LOCAL_RUN=true CYPRESS_SKIP_OKTA=true CYPRESS_CHECK_COMMIT=$(git rev-parse HEAD) CYPRESS_CHECK_URL=/health/commit cypress open --e2e --project ./../ --config-file cypress/cypress.config.js --config baseUrl=http://localhost:3000",
+ "e2e:local": "CYPRESS_IS_LOCAL_RUN=true CYPRESS_SKIP_OKTA=true CYPRESS_CHECK_COMMIT=$(git rev-parse HEAD) CYPRESS_CHECK_URL=/health/commit cypress open --e2e --project ./../ --config-file cypress/cypress.config.js --config baseUrl=http://localhost:3000,video=false",
+ "e2e:local:run": "CYPRESS_IS_LOCAL_RUN=true CYPRESS_SKIP_OKTA=true CYPRESS_CHECK_COMMIT=$(git rev-parse HEAD) CYPRESS_CHECK_URL=/health/commit cypress run --e2e --project ./../ --config-file cypress/cypress.config.js --browser=chrome --config baseUrl=http://localhost:3000",
"e2e:local:okta": "env $(cat ./../.env | grep -v \"#\" | xargs) CYPRESS_IS_LOCAL_RUN=true CYPRESS_CHECK_COMMIT=$(git rev-parse HEAD) CYPRESS_CHECK_URL=/health/commit cypress open --e2e --project ./../ --config-file cypress/cypress.config.js --config baseUrl=http://localhost:3000",
"e2e:nginx": "env $(cat ./../.env | grep -v \"#\" | xargs) CYPRESS_SKIP_OKTA=true CYPRESS_CHECK_COMMIT=$(git rev-parse HEAD) CYPRESS_CHECK_URL=/health/commit cypress open --e2e --project ./../ --config-file cypress/cypress.config.js --config baseUrl=https://localhost.simplereport.gov/app",
"e2e:nginx:okta": "env $(cat ./../.env | grep -v \"#\" | xargs) CYPRESS_CHECK_COMMIT=$(git rev-parse HEAD) CYPRESS_CHECK_URL=/health/commit cypress open --e2e --project ./../ --config-file cypress/cypress.config.js --config baseUrl=https://localhost.simplereport.gov/app"
diff --git a/cypress/support/commands.js b/cypress/support/commands.js
index d523fd5a2b..cbbdb06eb0 100644
--- a/cypress/support/commands.js
+++ b/cypress/support/commands.js
@@ -93,12 +93,6 @@ Cypress.Commands.add("login", () => {
});
});
-Cypress.Commands.add("restartWiremock", (stubDir) => {
- cy.clearCookies();
- cy.task("stopWiremock");
- cy.task("startWiremock", { stubDir });
-});
-
Cypress.Commands.add("selectFacility", () => {
cy.get("body").then(($body) => {
if (
@@ -145,6 +139,10 @@ Cypress.Commands.add("removeOrganizationAccess", () => {
});
+Cypress.Commands.add("resetWiremock", () => {
+ return !isLocalRun && cy.request("POST", "http://wiremock:8088/__admin/reset");
+});
+
Cypress.Commands.add("makePOSTRequest", (requestBody) => {
return cy.getLocalStorage('access_token').then(token => (cy.request(
{
@@ -162,3 +160,28 @@ Cypress.Commands.add("makePOSTRequest", (requestBody) => {
Cypress.Commands.add("injectSRAxe", () => {
return isLocalRun ? cy.injectAxe({ axeCorePath: './cypress/node_modules/axe-core/axe.min.js'}) : cy.injectAxe();
});
+
+// Print cypress-axe violations to the terminal
+function printAccessibilityViolations(violations) {
+ cy.task(
+ 'table',
+ violations.map(({id, impact, description, nodes}) => ({
+ id,
+ impact,
+ description,
+ "node count": nodes.length,
+ })),
+ );
+
+ cy.task('print', "Nodes:")
+ violations.forEach(({nodes})=> {
+ nodes.forEach(node => {
+ cy.task('print', node.html)
+ cy.task('print', "=============\n")
+ })
+ })
+}
+
+Cypress.Commands.add('checkAccessibility', () => {
+ cy.checkA11y(null, null, printAccessibilityViolations);
+});
\ No newline at end of file
diff --git a/cypress/support/e2e.js b/cypress/support/e2e.js
index 60f85254dd..9dd943f444 100644
--- a/cypress/support/e2e.js
+++ b/cypress/support/e2e.js
@@ -17,9 +17,6 @@
import "./commands";
import 'cypress-axe';
-// Alternatively you can use CommonJS syntax:
-// require('./commands')
-
const faker = require("faker");
const dayjs = require("dayjs");
diff --git a/cypress/support/wiremock/download-wiremock.sh b/cypress/support/wiremock/download-wiremock.sh
deleted file mode 100755
index dd7498c9e8..0000000000
--- a/cypress/support/wiremock/download-wiremock.sh
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/bin/bash
-
-if [[ ! -f "wiremock-jre8-standalone-2.29.1.jar" ]]; then
- curl -s -O https://repo1.maven.org/maven2/com/github/tomakehurst/wiremock-jre8-standalone/2.29.1/wiremock-jre8-standalone-2.29.1.jar
-fi
\ No newline at end of file
diff --git a/cypress/support/wiremock/ping-wiremock.sh b/cypress/support/wiremock/ping-wiremock.sh
deleted file mode 100755
index 4e5e868987..0000000000
--- a/cypress/support/wiremock/ping-wiremock.sh
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-
-printf 'Waiting for wiremock to start...'
-curl -k http://localhost:8088 > /dev/null 2>&1
-result=$?
-
-polls=0
-while [[ $result -ne 0 && $polls -lt 180 ]]; do
- ((polls++))
- printf .
- sleep 1
- curl -k http://localhost:8088 > /dev/null 2>&1
- result=$?
-done
-echo
-
-echo 'Wiremock is online! Starting Cypress tests...'
\ No newline at end of file
diff --git a/cypress/support/wiremock/start-wiremock.sh b/cypress/support/wiremock/start-wiremock.sh
deleted file mode 100755
index 42a5b0e2c7..0000000000
--- a/cypress/support/wiremock/start-wiremock.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/bash
-
-java -jar ./wiremock-jre8-standalone-2.29.1.jar --local-response-templating --port 8088 --root-dir ./cypress/stubs/$1
\ No newline at end of file
diff --git a/cypress/support/wiremock/stop-wiremock.sh b/cypress/support/wiremock/stop-wiremock.sh
deleted file mode 100755
index 285ec78a59..0000000000
--- a/cypress/support/wiremock/stop-wiremock.sh
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/bin/bash
-
-curl -s -f -X POST http://localhost:8088/__admin/shutdown
-
-echo 'Stopped Wiremock.'
\ No newline at end of file
diff --git a/docker-compose.ci.yml b/docker-compose.ci.yml
index c46ca327f6..bcc13b6c84 100644
--- a/docker-compose.ci.yml
+++ b/docker-compose.ci.yml
@@ -5,16 +5,7 @@ services:
SPRING_LIQUIBASE_ENABLED: "true"
GIT_DISCOVERY_ACROSS_FILESYSTEM: 1
frontend:
- environment:
- REACT_APP_BASE_URL: https://localhost.simplereport.gov
- REACT_APP_BACKEND_URL: https://localhost.simplereport.gov/api
- PUBLIC_URL: /app/
- REACT_APP_OKTA_ENABLED: "false"
- REACT_APP_DISABLE_MAINTENANCE_BANNER: "true"
- GIT_DISCOVERY_ACROSS_FILESYSTEM: 1
- command: ["./ci-git-fix.sh"]
- nginx:
- hostname: localhost.simplereport.gov
+ image: ghcr.io/cdcgov/prime-simplereport/frontend-lighthouse:${DOCKER_FRONTEND_LIGHTHOUSE_IMAGE_VERSION:-latest}
mailhog:
profiles:
- donotstart
\ No newline at end of file
diff --git a/docker-compose.cypress.yml b/docker-compose.cypress.yml
index e6977e58ff..a456652ab2 100644
--- a/docker-compose.cypress.yml
+++ b/docker-compose.cypress.yml
@@ -17,22 +17,15 @@ services:
CYPRESS_BACKEND_URL: $CYPRESS_BACKEND_URL
SPEC_PATH: $SPEC_PATH
TEST_ENV: $TEST_ENV
+ depends_on:
+ - backend
+ - frontend
+ - wiremock
+ - nginx
volumes:
- - ./cypress/fixtures/:/app/cypress/fixtures/
- - ./cypress/e2e/:/app/cypress/e2e/
- - ./cypress/node_modules/:/app/cypress/node_modules/
- - ./cypress/plugins/:/app/cypress/plugins/
- ./cypress/screenshots/:/app/cypress/screenshots/
- - ./cypress/stubs/:/app/cypress/stubs/
- - ./cypress/support/:/app/cypress/support/
- ./cypress/videos/:/app/cypress/videos/
- - ./cypress/cypress.config.js:/app/cypress/cypress.config.js
- - ./cypress/package.json:/app/package.json
- - ./cypress/yarn.lock:/app/yarn.lock
- - ./cypress/e2e.sh:/app/e2e.sh
- ./.git/:/app/.git/
- expose:
- - "8088"
command:
["-s", "$SPEC_PATH", "-r", "$TEST_ENV"]
backend:
@@ -46,22 +39,20 @@ services:
WIREMOCK_URL: $WIREMOCK_URL
SPRING_LIQUIBASE_ENABLED: "true"
GIT_DISCOVERY_ACROSS_FILESYSTEM: 1
- frontend:
- environment:
- REACT_APP_OKTA_URL: $WIREMOCK_URL
- REACT_APP_BASE_URL: https://localhost.simplereport.gov
- REACT_APP_BACKEND_URL: https://localhost.simplereport.gov/api
- PUBLIC_URL: /app/
- REACT_APP_OKTA_ENABLED: "true"
- REACT_APP_DISABLE_MAINTENANCE_BANNER: "true"
- GIT_DISCOVERY_ACROSS_FILESYSTEM: 1
- command: ["./ci-git-fix.sh"]
- nginx:
- hostname: localhost.simplereport.gov
- environment:
- NGINX_ENTRYPOINT_QUIET_LOGS: 1
+ depends_on:
+ - db
+ - wiremock
mailhog:
profiles:
- donotstart
db:
- command: -p ${SR_DB_PORT:-5432} -c shared_buffers=512MB -c max_connections=500
\ No newline at end of file
+ command: -p ${SR_DB_PORT:-5432} -c shared_buffers=512MB -c max_connections=500
+ wiremock:
+ image: wiremock/wiremock:2.32.0-alpine
+ volumes:
+ - ./wiremock/stubs/:/home/wiremock
+ container_name: wiremock
+ restart: "unless-stopped"
+ command: --local-response-templating --port=8088
+ expose:
+ - "8088"
\ No newline at end of file
diff --git a/docker-compose.yml b/docker-compose.yml
index 9c0afd654e..370abdbbfa 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -33,7 +33,8 @@ services:
# Spring Boot backend
backend:
build:
- context: backend
+ context: ./
+ dockerfile: backend/Dockerfile
image: ghcr.io/cdcgov/prime-simplereport/backend:${DOCKER_BACKEND_IMAGE_VERSION:-latest}
container_name: backend
env_file:
@@ -42,9 +43,6 @@ services:
SPRING_PROFILES_ACTIVE: okta-local,db-dockerized,create-sample-data
SPRING_LIQUIBASE_ENABLED: "true"
GIT_DISCOVERY_ACROSS_FILESYSTEM: 1
- volumes:
- - ./.git:/app/.git
- - ./backend:/app/backend/
depends_on:
- db
expose:
@@ -52,21 +50,19 @@ services:
# React frontend
frontend:
build:
- context: frontend
+ context: ./
+ dockerfile: frontend/Dockerfile
+ args:
+ REACT_APP_OKTA_URL: $REACT_APP_OKTA_URL
+ REACT_APP_BASE_URL: $REACT_APP_BASE_URL
+ REACT_APP_BACKEND_URL: $REACT_APP_BACKEND_URL
+ REACT_APP_OKTA_CLIENT_ID: $REACT_APP_OKTA_CLIENT_ID
+ PUBLIC_URL: $PUBLIC_URL
+ REACT_APP_OKTA_ENABLED: $REACT_APP_OKTA_ENABLED
+ REACT_APP_DISABLE_MAINTENANCE_BANNER: "true"
+ GIT_DISCOVERY_ACROSS_FILESYSTEM: 1
image: ghcr.io/cdcgov/prime-simplereport/frontend:${DOCKER_FRONTEND_IMAGE_VERSION:-latest}
container_name: frontend
- environment:
- REACT_APP_BASE_URL: https://localhost.simplereport.gov
- REACT_APP_BACKEND_URL: https://localhost.simplereport.gov/api
- PUBLIC_URL: /app/
- REACT_APP_OKTA_ENABLED: "true"
- REACT_APP_DISABLE_MAINTENANCE_BANNER: "true"
- GIT_DISCOVERY_ACROSS_FILESYSTEM: 1
- volumes:
- - ./.git:/app/.git
- - ./frontend:/app/frontend/
- - node_modules:/app/frontend/node_modules
- - ./backend/src/main/resources/graphql:/app/backend/src/main/resources/graphql
expose:
- "3000"
# This is an nginx server that serves both the frontend and the backend
@@ -76,12 +72,13 @@ services:
context: nginx
image: ghcr.io/cdcgov/prime-simplereport/nginx:${DOCKER_NGINX_IMAGE_VERSION:-latest}
container_name: nginx
+ hostname: localhost.simplereport.gov
+ restart: "unless-stopped"
+ environment:
+ NGINX_ENTRYPOINT_QUIET_LOGS: 1
depends_on:
- backend
- frontend
- volumes:
- - ./certs:/etc/nginx/certs
- - ./frontend/public/index.html:/etc/nginx/html/index.html
ports:
- "80:80"
- "443:443"
@@ -90,7 +87,6 @@ services:
- '1025:1025'
- '8025:8025'
image: mailhog/mailhog
-
volumes:
db-data:
node_modules:
diff --git a/frontend/Dockerfile b/frontend/Dockerfile
index 973c7da635..af07161d09 100644
--- a/frontend/Dockerfile
+++ b/frontend/Dockerfile
@@ -1,21 +1,61 @@
-FROM node:18-alpine
+FROM node:18-alpine as build
LABEL org.opencontainers.image.source https://github.com/CDCgov/prime-simplereport
# Add bash and git
-RUN apk add --no-cache bash git
+RUN apk add --no-cache git
+
+ARG REACT_APP_BASE_URL
+ARG REACT_APP_BACKEND_URL
+ARG PUBLIC_URL
+ARG REACT_APP_OKTA_URL
+ARG REACT_APP_OKTA_ENABLED
+ARG REACT_APP_DISABLE_MAINTENANCE_BANNER
+ARG GIT_DISCOVERY_ACROSS_FILESYSTEM
+ARG REACT_APP_OKTA_CLIENT_ID
+
+
+ENV REACT_APP_BASE_URL $REACT_APP_BASE_URL
+ENV REACT_APP_BACKEND_URL $REACT_APP_BACKEND_URL
+ENV PUBLIC_URL $PUBLIC_URL
+ENV REACT_APP_OKTA_URL $REACT_APP_OKTA_URL
+ENV REACT_APP_OKTA_ENABLED $REACT_APP_OKTA_ENABLED
+ENV REACT_APP_DISABLE_MAINTENANCE_BANNER $REACT_APP_DISABLE_MAINTENANCE_BANNER
+ENV GIT_DISCOVERY_ACROSS_FILESYSTEM $GIT_DISCOVERY_ACROSS_FILESYSTEM
+ENV REACT_APP_OKTA_CLIENT_ID $REACT_APP_OKTA_CLIENT_ID
+
# Create directory for app, grant ownership to node user
RUN mkdir -p /app/frontend/node_modules
-RUN chown -R node:node /app
+
WORKDIR /app/frontend
-# Run app as non-privileged user
-USER node
+# Copy over yarn dependency files before src
+# so it caches via docker for subsequent builds
+COPY ./frontend/package.json /app/frontend/
+COPY ./frontend/yarn.lock /app/frontend/
# Install dependencies
-COPY package.json yarn.lock /app/frontend/
RUN yarn install --non-interactive
-CMD ["yarn", "start"]
+# copy over the backend graphql schema files
+ADD ./backend/ /app/backend
+ADD ./frontend /app/frontend
+ADD ./.git /app/.git
+
+#e2e specific, disable content security
+RUN echo "REACT_APP_CONTENT_SECURITY_POLICY_DEFAULT_SRC=''" >> .env.production.local
+RUN echo "REACT_APP_CONTENT_SECURITY_POLICY_SCRIPT_SRC=''" >> .env.production.local
+
+RUN yarn run build
+
+# production environment
+FROM node:18-alpine
+RUN npm install -g serve
+WORKDIR /app/frontend
+COPY --from=build /app/frontend/build /app/frontend/build
+
+# Run app as non-privileged user
+USER node
-EXPOSE 3000
\ No newline at end of file
+EXPOSE 3000
+CMD ["serve", "-s", "build"]
diff --git a/frontend/ci-git-fix.sh b/frontend/ci-git-fix.sh
deleted file mode 100755
index 0aa0b8b64c..0000000000
--- a/frontend/ci-git-fix.sh
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/bin/bash
-
-echo "git config --global --add safe.directory /app"
-git config --global --add safe.directory /app
-
-yarn start
diff --git a/frontend/package.json b/frontend/package.json
index 6c1b7f2ef0..31ad1e7d0c 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -99,15 +99,6 @@
"jest-dom"
],
"rules": {
- "graphql/template-strings": [
- "error",
- {
- "env": "apollo"
- }
- ],
- "graphql/named-operations": [
- "error"
- ],
"import/no-unresolved": 0,
"import/first": 1,
"import/order": [
diff --git a/frontend/src/app/commonComponents/RadioGroup.tsx b/frontend/src/app/commonComponents/RadioGroup.tsx
index e5ddbe6851..a028d528e3 100644
--- a/frontend/src/app/commonComponents/RadioGroup.tsx
+++ b/frontend/src/app/commonComponents/RadioGroup.tsx
@@ -123,7 +123,11 @@ const RadioGroup = ({
onBlur={onBlur}
{...registrationProps}
/>
-