Skip to content

Commit

Permalink
Merge branch 'master' into platform/david-navapbc/13925/singleton_htt…
Browse files Browse the repository at this point in the history
…p_client/redux
  • Loading branch information
david-navapbc authored Aug 27, 2024
2 parents 31f23dd + 69486b4 commit 184db65
Show file tree
Hide file tree
Showing 78 changed files with 2,146 additions and 2,031 deletions.
2 changes: 1 addition & 1 deletion .github/actions/build-backend/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ runs:
distribution: "temurin"
cache: "gradle"

- uses: gradle/actions/setup-gradle@af1da67850ed9a4cedd57bfd976089dd991e2582
- uses: gradle/actions/setup-gradle@16bf8bc8fe830fa669c3c9f914d3eb147c629707

- name: Lint
if: inputs.run-integration-tests == 'true'
Expand Down
70 changes: 70 additions & 0 deletions .github/actions/build-submissions/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# action.yml
name: "Build Submissions"
description: "Build submissions microservice"
inputs:
version:
description: "Version tag"
required: true
upload-build:
default: true
run-integration-tests:
default: false
run-qc:
default: false
github-token:
default: false
sp-creds:
description: "Azure Service Principal creds"

runs:
using: "composite"
steps:
# These are for CI and not credentials of any system
- name: Set Environment Variables
working-directory: prime-router
shell: bash
run: |
echo >> $GITHUB_ENV DB_USER='prime'
echo >> $GITHUB_ENV DB_PASSWORD='changeIT!'
- name: Remove unnecessary software
shell: bash
run: |
sudo rm -rf /usr/local/lib/android
- name: Set up JDK 17
uses: actions/setup-java@6a0805fcefea3d4657a47ac4c165951e33482018
with:
java-version: "17"
distribution: "temurin"
cache: "gradle"

- uses: gradle/actions/setup-gradle@af1da67850ed9a4cedd57bfd976089dd991e2582

- name: Lint
if: inputs.run-integration-tests == 'true'
run: ./gradlew :submissions:ktlintCheck
shell: bash

- name: Spin up build containers
working-directory: prime-router
shell: bash
run: docker compose -f docker-compose.postgres.yml up -d

- name: Build Submissions Package
uses: ./.github/actions/retry
with:
timeout_minutes: 10
max_attempts: 2
retry_wait_seconds: 30
command: |
./gradlew :submissions:build -x test
shell: bash

- name: Cleanup Gradle Cache
if: inputs.run-integration-tests == 'true'
working-directory: prime-router
run: |
rm -f .gradle/caches/modules-2/modules-2.lock
rm -f .gradle/caches/modules-2/gc.properties
shell: bash
6 changes: 3 additions & 3 deletions .github/actions/sonarcloud/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ runs:
args: >
-Dsonar.coverage.exclusions=prime-router/src/test/**,prime-router/src/testIntegration/**,prime-router/src/main/kotlin/cli/tests/**,frontend-react/**/__mocks__/**,frontend-react/**/mocks/**,frontend-react/**/*.test.*
-Dsonar.cpd.exclusions=frontend-react/**/*.test.*,prime-router/src/test/**,prime-router/src/testIntegration/**,prime-router/src/main/kotlin/cli/tests/**
-Dsonar.sources=frontend-react/src,prime-router/src
-Dsonar.sources=frontend-react/src,prime-router/src,submissions/src,shared/src
-Dsonar.projectKey=CDCgov_prime-data-hub
-Dsonar.organization=cdcgov
-Dsonar.java.binaries=prime-router/build/classes/java/main,prime-router/build/classes/kotlin/main
-Dsonar.java.libraries=prime-router/build/libs/*.jar,prime-router/build/**/*.jar
-Dsonar.java.binaries=prime-router/build/classes/java/main,prime-router/build/classes/kotlin/main,submissions/build/classes/kotlin/main,shared/build/classes/kotlin/main
-Dsonar.java.libraries=prime-router/build/libs/*.jar,prime-router/build/**/*.jar,submissions/build/**/*.jar,shared/build/**/*.jar
-Dsonar.coverage.jacoco.xmlReportPaths=prime-router/build/reports/jacoco/test/jacocoTestReport.xml
-Dsonar.javascript.lcov.reportPaths=frontend-react/coverage/lcov.info
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/snyk.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ jobs:
java-version: "17"
distribution: "temurin"
cache: "gradle"
- uses: gradle/actions/setup-gradle@af1da67850ed9a4cedd57bfd976089dd991e2582
- uses: gradle/actions/setup-gradle@16bf8bc8fe830fa669c3c9f914d3eb147c629707
- name: Snyk Monitor
working-directory: ${{ matrix.folder }}
run: snyk monitor --org=prime-reportstream
Expand Down
6 changes: 5 additions & 1 deletion .github/workflows/sonarcloud.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ jobs:

- name: Gradle setup
if: steps.changed-files-yaml.outputs.backend_any_changed == 'true' || steps.branch-name.outputs.is_default == 'true'
uses: gradle/actions/setup-gradle@af1da67850ed9a4cedd57bfd976089dd991e2582
uses: gradle/actions/setup-gradle@16bf8bc8fe830fa669c3c9f914d3eb147c629707

- name: Spin up build containers
if: steps.changed-files-yaml.outputs.backend_any_changed == 'true' || steps.branch-name.outputs.is_default == 'true'
Expand All @@ -93,6 +93,10 @@ jobs:
command: ./gradlew -Dorg.gradle.jvmargs="-Xmx6g" :prime-router:package -x fatjar
shell: bash

- name: Build Submissions Package
if: steps.changed-files-yaml.outputs.backend_any_changed == 'true' || steps.branch-name.outputs.is_default == 'true'
uses: ./.github/actions/build-submissions

- name: Perform Java CodeQL Analysis
if: steps.changed-files-yaml.outputs.backend_any_changed == 'true' || steps.branch-name.outputs.is_default == 'true'
uses: github/codeql-action/analyze@v3
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/validate_terraform.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ jobs:
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332

- name: Run Checkov action
uses: bridgecrewio/checkov-action@b57df8031953b36872c225e6627691100b03bcde
uses: bridgecrewio/checkov-action@1b813e8f72afe2b6263a6ea10c873707e21ebe44
with:
directory: operations/app/terraform
skip_check: CKV_AZURE_139,CKV_AZURE_137,CKV_AZURE_103,CKV_AZURE_104,CKV_AZURE_102,CKV_AZURE_130,CKV_AZURE_121,CKV_AZURE_67,CKV_AZURE_56,CKV_AZURE_17,CKV_AZURE_63,CKV_AZURE_18,CKV_AZURE_88,CKV_AZURE_65,CKV_AZURE_13,CKV_AZURE_66,CKV_AZURE_33,CKV_AZURE_35,CKV_AZURE_36,CKV_AZURE_98,CKV2_AZURE_1,CKV2_AZURE_15,CKV2_AZURE_21,CKV_AZURE_213,CKV_AZURE_59,CKV2_AZURE_33,CKV2_AZURE_32,CKV2_AZURE_28,CKV_AZURE_206,CKV_AZURE_42,CKV_AZURE_110,CKV_AZURE_109,CKV_AZURE_166,CKV2_AZURE_38,CKV2_AZURE_40,CKV2_AZURE_41,CKV_AZURE_235
1 change: 1 addition & 0 deletions frontend-react/.eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ module.exports = {
// TODO: investigate these for reconsideration or per-module ignoring
"playwright/no-conditional-in-test": ["off"],
"playwright/no-force-option": ["off"],
"playwright/expect-expect": ["off"],
},
},
],
Expand Down
67 changes: 54 additions & 13 deletions frontend-react/e2e/helpers/internal-links.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,58 @@
import { Page } from "@playwright/test";

export const ELC =
"https://www.cdc.gov/epidemiology-laboratory-capacity/php/about/";
export const ELC = "https://www.cdc.gov/epidemiology-laboratory-capacity/php/about/";

export async function clickOnInternalLink(
locator: string,
dataTestId: string,
linkName: string,
page: Page,
) {
await page
.locator(locator)
.getByTestId(dataTestId)
.getByRole("link", { name: linkName })
.click();
export async function clickOnInternalLink(locator: string, dataTestId: string, linkName: string, page: Page) {
await page.locator(locator).getByTestId(dataTestId).getByRole("link", { name: linkName }).click();
}

export interface SideNavItem {
name: string;
path: string;
}

export const aboutSideNav = [
{
name: "About",
path: "/about",
},
{
name: "Our network",
path: "/about/our-network",
},
{
name: "Product roadmap",
path: "/about/roadmap",
},
{
name: "News",
path: "/about/news",
},
{
name: "Case studies",
path: "/about/case-studies",
},
{
name: "Security",
path: "/about/security",
},
{
name: "Release notes",
path: "/about/release-notes",
},
];

export const gettingStartedSideNav = [
{
name: "Getting started",
path: "/getting-started",
},
{
name: "Sending data",
path: "/getting-started/sending-data",
},
{
name: "Receiving data",
path: "/getting-started/receiving-data",
},
];
102 changes: 50 additions & 52 deletions frontend-react/e2e/pages/BasePage.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { SideNavItem } from "../helpers/internal-links";
import { selectTestOrg } from "../helpers/utils";
import appInsightsConfig from "../mocks/appInsightsConfig.json" assert { type: "json" };
import { Locator, Page, Request, Response, Route, TestArgs } from "../test";
import { expect, Locator, Page, Request, Response, Route, TestArgs } from "../test";

export type RouteHandlers = Record<string, Parameters<Page["route"]>[1]>;
export type MockRouteCache = Record<string, RouteFulfillOptions>;
Expand All @@ -12,25 +13,12 @@ export interface BasePageProps {
heading?: Locator;
}

export type RouteFulfillOptions = Exclude<
Parameters<Route["fulfill"]>[0],
undefined
> & { isMock?: boolean };
export type RouteFulfillOptionsFn = (
request: Request,
) => Promise<RouteFulfillOptions> | RouteFulfillOptions;
export type RouteFulfillOptions = Exclude<Parameters<Route["fulfill"]>[0], undefined> & { isMock?: boolean };
export type RouteFulfillOptionsFn = (request: Request) => Promise<RouteFulfillOptions> | RouteFulfillOptions;
export type RouteHandlerFn = (route: Route, request: Request) => Promise<void>;
export type RouteHandlerFulfillOptions =
| RouteFulfillOptions
| RouteFulfillOptionsFn;
export type RouteHandlerFulfillEntry = [
url: string,
fulfillOptions: RouteHandlerFulfillOptions,
];
export type ResponseHandlerEntry = [
url: string,
handler: (response: Response) => Promise<void> | void,
];
export type RouteHandlerFulfillOptions = RouteFulfillOptions | RouteFulfillOptionsFn;
export type RouteHandlerFulfillEntry = [url: string, fulfillOptions: RouteHandlerFulfillOptions];
export type ResponseHandlerEntry = [url: string, handler: (response: Response) => Promise<void> | void];
export type RouteHandlerEntry = [url: string, handler: RouteHandlerFn];

export interface GotoRouteHandlerOptions {
Expand Down Expand Up @@ -70,10 +58,7 @@ export abstract class BasePage {
readonly heading: Locator;
readonly footer: Locator;

constructor(
{ url, title, heading }: BasePageProps,
testArgs: BasePageTestArgs,
) {
constructor({ url, title, heading }: BasePageProps, testArgs: BasePageTestArgs) {
this.page = testArgs.page;
this.url = url;
this.title = title;
Expand All @@ -94,9 +79,7 @@ export abstract class BasePage {
return this._mockError;
}

set mockError(
err: boolean | number | RouteHandlerFulfillOptions | undefined,
) {
set mockError(err: boolean | number | RouteHandlerFulfillOptions | undefined) {
if (err == null || err === false) {
this._mockError = undefined;
return;
Expand Down Expand Up @@ -151,6 +134,39 @@ export abstract class BasePage {
);
}

async testHeader() {
await expect(this.page).toHaveTitle(this.title);
await expect(this.heading).toBeVisible();
}

async testCard(card: { name: string }) {
const cardHeader = this.page.locator(".usa-card__header", {
hasText: card.name,
});

await expect(cardHeader).toBeVisible();
}

async testSidenav(navItems: SideNavItem[]) {
const sideNav = this.page.getByTestId("sidenav");

for (const navItem of navItems) {
const link = sideNav.locator(`a`, { hasText: navItem.name });

await expect(link).toBeVisible();
await expect(link).toHaveAttribute("href", navItem.path);
}
}

async testFooter() {
await expect(this.page.locator("footer")).toBeAttached();
await this.page.locator("footer").scrollIntoViewIfNeeded();
await expect(this.page.locator("footer")).toBeInViewport();
await expect(this.page.getByTestId("govBanner")).not.toBeInViewport();
await this.page.evaluate(() => window.scrollTo(0, 0));
await expect(this.page.getByTestId("govBanner")).toBeInViewport();
}

/**
* Used to select the test org if logged-in user is Admin and the isTestOrg prop is set to true.
* This is needed for smoke tests since they use live data.
Expand Down Expand Up @@ -210,19 +226,11 @@ export abstract class BasePage {
const wrapped = items.map(([url, _fulfillOptions]) => {
const fn = async (request: Request) => {
const fulfillOptions =
typeof _fulfillOptions === "function"
? await _fulfillOptions(request)
: _fulfillOptions;
typeof _fulfillOptions === "function" ? await _fulfillOptions(request) : _fulfillOptions;
const mockErrorFulfillOptions =
typeof this.mockError === "function"
? await this.mockError(request)
: this.mockError;
const mockCacheFulfillOptions = this.getMockCacheFulfillOptions(
url,
fulfillOptions,
);
const mockOverrideFulfillOptions =
mockErrorFulfillOptions ?? mockCacheFulfillOptions;
typeof this.mockError === "function" ? await this.mockError(request) : this.mockError;
const mockCacheFulfillOptions = this.getMockCacheFulfillOptions(url, fulfillOptions);
const mockOverrideFulfillOptions = mockErrorFulfillOptions ?? mockCacheFulfillOptions;

return {
isMock: true,
Expand All @@ -233,9 +241,7 @@ export abstract class BasePage {
});

wrapped.forEach(([url, fn]) =>
this.mockRouteHandlers.set(url, async (route, req) =>
route.fulfill(await fn(req)),
),
this.mockRouteHandlers.set(url, async (route, req) => route.fulfill(await fn(req))),
);

return wrapped;
Expand All @@ -244,15 +250,10 @@ export abstract class BasePage {
/**
* Helper function to convert RouteHandlerFulfillEntries to RouteHandlerEntries.
*/
createRouteHandlers(
items: RouteHandlerFulfillEntry[],
): RouteHandlerEntry[] {
createRouteHandlers(items: RouteHandlerFulfillEntry[]): RouteHandlerEntry[] {
return items.map(([url, _fulfill]) => {
const handler = async (route: Route, request: Request) => {
const fulfill =
typeof _fulfill === "function"
? await _fulfill(request)
: _fulfill;
const fulfill = typeof _fulfill === "function" ? await _fulfill(request) : _fulfill;

return route.fulfill(fulfill);
};
Expand Down Expand Up @@ -302,10 +303,7 @@ export abstract class BasePage {
* Get or warm the cache for a particular mock URL's fulfillOptions. This
* allows for dynamic options to persist across page reloads for consistency.
*/
getMockCacheFulfillOptions(
url: string,
fulfillOptions: RouteFulfillOptions,
) {
getMockCacheFulfillOptions(url: string, fulfillOptions: RouteFulfillOptions) {
const cache = this._mockRouteCache[url];
if (!cache) {
this._mockRouteCache[url] = fulfillOptions;
Expand Down
Loading

0 comments on commit 184db65

Please sign in to comment.