Skip to content

Commit

Permalink
NO-REF: Fixing docker file and playwright tests (#547)
Browse files Browse the repository at this point in the history
  • Loading branch information
kylevillegas93 authored Oct 25, 2024
1 parent 51ecb3c commit 5556a42
Show file tree
Hide file tree
Showing 16 changed files with 73 additions and 104 deletions.
4 changes: 2 additions & 2 deletions .env.test
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
APP_ENV=testing
APP_ENV=development

# API ENDPOINT
API_URL=https://backend.msw
API_URL=https://drb-api-qa.nypl.org/
30 changes: 24 additions & 6 deletions .github/workflows/Playwright.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
name: Playwright Tests for Digital Research Books

on:
pull_request:
# TODO: Remove https://drb-api-qa.nypl.org from behind the VPC
# on:
# pull_request:

jobs:
tests:
Expand All @@ -15,18 +16,35 @@ jobs:
with:
node-version-file: ".nvmrc"

- name: Install Deps
- name: Install Test Dependencies
run: npm i @cucumber/[email protected] @playwright/[email protected]

- name: Install Playwright
run: npx playwright install --with-deps

- name: Build app
run: NODE_ENV=test npm run build

- name: Start the app
run: npm run dev &
shell: bash

- name: Wait for the app
run: |
RETRIES=6
until curl --output /dev/null --silent --head --fail http://localhost:3000 || [ $((RETRIES--)) -eq 0 ]; do
echo "Waiting for http://localhost:3000"
sleep 5
done
if [ $RETRIES -lt 0 ]; then
echo "Failed to connect to http://localhost:3000"
exit 1
fi
shell: bash

- name: Run your tests
run: npm run playwright

- name: Install Playwright Browser Utils
run: npx playwright install --with-deps

- name: Set the world parameters as an env var
# WORLD_PARAMETERS set here will override anything set in cucumber.json
run: |
Expand Down
45 changes: 0 additions & 45 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -123,51 +123,6 @@ jobs:
- name: Test
run: npm run test

playwright_test:
name: Playwright Integration Tests
runs-on: ubuntu-latest
container:
image: mcr.microsoft.com/playwright:v1.46.0-jammy
env:
CI: true
steps:
- uses: actions/checkout@v4

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version-file: ".nvmrc"
cache: npm

- name: Cache node modules
uses: actions/cache@v4
env:
cache-name: cache-node-modules
with:
# npm cache files are stored in `~/.npm` on Linux/macOS
path: ~/.npm
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-build-${{ env.cache-name }}-
${{ runner.os }}-build-
${{ runner.os }}-
- name: Install Dependencies
run: npm ci

- name: Build app
run: NODE_ENV=test npm run build

- name: Test
run: npm run playwright

- uses: actions/upload-artifact@v4
if: always()
with:
name: playwright-report
path: /playwright-report/
retention-days: 4

docker_build:
# Don't push anything to ECR, just build the docker image to make sure there are no build failures
name: Build Docker Image
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,4 @@ newrelic_agent.log

# playwright
playwright-report
test-results
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## [Prerelease]
- Add submit feedback error handling and new fields
- Fix docker file and playwright tests

## [0.18.5]
- Make NYPL footer sticky
Expand Down
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ ARG NEXT_PUBLIC_ADOBE_ANALYTICS
ARG APP_ENV

# Build the app!
RUN npm run build

ENV PATH /app/node_modules/.bin:$PATH
ENV PORT=3000 \
NODE_ENV=production
Expand All @@ -32,6 +30,8 @@ ENV NEW_RELIC_APP_NAME $NEW_RELIC_APP_NAME
ENV NEXT_PUBLIC_ADOBE_ANALYTICS $NEXT_PUBLIC_ADOBE_ANALYTICS
ENV APP_ENV $APP_ENV

RUN npm run build

# RUNNER, copy all the files and run next
FROM base AS runner
WORKDIR /app
Expand Down
2 changes: 0 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
version: "3"

services:
web:
container_name: sfr-bookfinder-front-end
Expand Down
4 changes: 2 additions & 2 deletions mocks/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ import {
INVALID_COLLECTION_PATH,
DOWNLOAD_PATH,
FULFILL_PATH,
LIMITED_ACCESS_WORK_PATH,
WORK_PATH,
} from "./mockEnv";

const isAuthenticated = (request) => {
const auth = request.headers.get("authorization");
return auth === "Bearer access-token";
};

const workUrl = new URL(LIMITED_ACCESS_WORK_PATH, API_URL).toString();
const workUrl = new URL(WORK_PATH, API_URL).toString();
const fulfillUrl = new URL(FULFILL_PATH, API_URL).toString();
const downloadUrl = new URL(DOWNLOAD_PATH, API_URL).toString();
const collectionListUrl = new URL(COLLECTION_LIST_PATH, API_URL).toString();
Expand Down
8 changes: 3 additions & 5 deletions mocks/mockEnv.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
export const NYPL_LOGIN_URL = "https://login.nypl.org/auth/login?redirect_uri=";
export const API_URL = "https://backend.msw";
export const FULFILL_PATH = "/fulfill/12345";
export const LIMITED_ACCESS_WORK_PATH =
"/work/12345678-1234-1234-1234-1234567890ab";
export const FULFILL_PATH = "/fulfill/9351827";
export const LIMITED_ACCESS_EDITION_PATH = "/edition/6977884";
export const WORK_PATH = "/work/5950e6df-9d99-42fe-8924-1116166a2acb";
export const DOWNLOAD_PATH = "/test-download-pdf";
export const HOME_PATH = "/";
export const COLLECTION_LIST_PATH = "/collection/list";
export const COLLECTION_PATH =
"/collection/978ea0e0-8ecc-4de2-bfe8-032fea641d8e?page=1";
export const INVALID_COLLECTION_PATH = "/collection/invalid-collection";
27 changes: 12 additions & 15 deletions playwright/integration/auth.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ import { test, expect } from "../support/test-utils";
import {
API_URL,
FULFILL_PATH,
LIMITED_ACCESS_WORK_PATH,
LIMITED_ACCESS_EDITION_PATH,
NYPL_LOGIN_URL,
} from "~/mocks/mockEnv";
import { server } from "~/mocks/server";
import { LOGIN_TO_READ_TEST_ID } from "~/src/constants/testIds";

test.beforeEach(async ({ context }) => {
await context.clearCookies();
Expand All @@ -14,39 +15,35 @@ test.afterEach(() => server.resetHandlers());
test.afterAll(() => server.close());

test.describe("Cookie authentication", () => {
test("redirects to NYPL log in page with no cookie", async ({
page,
port,
}) => {
await page.goto(`http://localhost:${port}${LIMITED_ACCESS_WORK_PATH}`);
await page.getByRole("link", { name: "title Download PDF" }).click();
test("redirects to NYPL log in page with no cookie", async ({ page }) => {
await page.goto(`${LIMITED_ACCESS_EDITION_PATH}`);
await page.getByTestId(LOGIN_TO_READ_TEST_ID).click();
await page.waitForURL(`**${NYPL_LOGIN_URL}**`);
const url = new URL(page.url());
const redirectUri = url.searchParams.get("redirect_uri");

expect(redirectUri).toContain(LIMITED_ACCESS_WORK_PATH);
expect(redirectUri).toContain(LIMITED_ACCESS_EDITION_PATH);
});

test("redirects to NYPL login page with expired cookie", async ({
page,
port,
setCookie,
}) => {
const cookieExpiration = new Date("1970-01-01T00:00:00.000Z").getTime();
setCookie(cookieExpiration);

await page.goto(`http://localhost:${port}${LIMITED_ACCESS_WORK_PATH}`);
await page.getByRole("link", { name: "title Download PDF" }).click();
await page.goto(`${LIMITED_ACCESS_EDITION_PATH}`);
await page.getByTestId(LOGIN_TO_READ_TEST_ID).click();
await page.waitForURL(`**${NYPL_LOGIN_URL}**`);
const url = new URL(page.url());
const redirectUri = url.searchParams.get("redirect_uri");

expect(redirectUri).toContain(LIMITED_ACCESS_WORK_PATH);
expect(redirectUri).toContain(LIMITED_ACCESS_EDITION_PATH);
});

test("redirects to download with valid auth cookie", async ({
// TODO: logging in from localhost does not work
test.skip("redirects to download with valid auth cookie", async ({
page,
port,
setCookie,
context,
}) => {
Expand All @@ -58,7 +55,7 @@ test.describe("Cookie authentication", () => {

expect(authCookie.path).toBe("/");

await page.goto(`http://localhost:${port}${LIMITED_ACCESS_WORK_PATH}`);
await page.goto(`${LIMITED_ACCESS_EDITION_PATH}`);

const responsePromise = page.waitForResponse(`${API_URL}${FULFILL_PATH}`);
await page.getByRole("link", { name: "title Download PDF" }).click();
Expand Down
37 changes: 14 additions & 23 deletions playwright/integration/landing.spec.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,24 @@
import { test, expect } from "../support/test-utils";
import {
INVALID_COLLECTION_PATH,
HOME_PATH,
COLLECTION_PATH,
} from "~/mocks/mockEnv";
import { INVALID_COLLECTION_PATH, HOME_PATH } from "~/mocks/mockEnv";
import { server } from "~/mocks/server";
import {
SEARCH_BAR_TEST_ID,
ERROR_LAYOUT_TEST_ID,
} from "~/src/constants/testIds";

test.afterEach(() => server.resetHandlers());
test.afterAll(() => server.close());

test("View landing page with collection", async ({ page, port }) => {
await page.goto(`http://localhost:${port}${HOME_PATH}`);
const collectionHeading = page.getByRole("heading", {
name: "Recently Added Collections",
level: 2,
});
expect(collectionHeading).toBeVisible();
const collectionLink = await page
.getByRole("link", {
name: /Baseball: A Collection by Mike Benowitz/,
})
.getAttribute("href");
expect(collectionLink).toContain(COLLECTION_PATH);
test("View landing page with search", async ({ page }) => {
await page.goto(`${HOME_PATH}`);

const searchBar = page.getByTestId(SEARCH_BAR_TEST_ID);
await expect(searchBar).toBeVisible();
});

test("Shows error boundary for invalid collection", async ({ page, port }) => {
await page.goto(`http://localhost:${port}${INVALID_COLLECTION_PATH}`);
test("Shows error page for invalid collection", async ({ page }) => {
await page.goto(`${INVALID_COLLECTION_PATH}`);

const alert = page.getByRole("alert");
const errorText = alert.getByText("Something went wrong on our end");
await expect(errorText).toBeVisible();
const errorLayout = page.getByTestId(ERROR_LAYOUT_TEST_ID);
await expect(errorLayout).toBeVisible();
});
3 changes: 2 additions & 1 deletion src/components/EditionCard/DownloadLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { trackCtaClick } from "~/src/lib/adobe/Analytics";
import { fulfillFetcher } from "~/src/lib/api/SearchApi";
import { ItemLink } from "~/src/types/DataModel";
import { formatUrl } from "~/src/util/Util";
import { LOGIN_TO_DOWNLOAD_TEST_ID } from "~/src/constants/testIds";

const DownloadLink: React.FC<{
downloadLink: ItemLink;
Expand Down Expand Up @@ -73,7 +74,7 @@ const DownloadLink: React.FC<{
}

return (
<Box>
<Box data-testid={LOGIN_TO_DOWNLOAD_TEST_ID}>
<Link
to={`${linkUrl}`}
linkType="buttonSecondary"
Expand Down
3 changes: 2 additions & 1 deletion src/components/EditionCard/ReadOnlineLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import React from "react";
import Link from "~/src/components/Link/Link";
import { LOGIN_LINK_BASE } from "~/src/constants/links";
import { ItemLink } from "~/src/types/DataModel";
import { LOGIN_TO_READ_TEST_ID } from "~/src/constants/testIds";

// "Read Online" button should only show up if the link was flagged as "reader" or "embed"
const ReadOnlineLink: React.FC<{
Expand All @@ -27,7 +28,7 @@ const ReadOnlineLink: React.FC<{

return (
readOnlineLink && (
<Box>
<Box data-testid={LOGIN_TO_READ_TEST_ID}>
<Link
to={linkUrl}
linkType="button"
Expand Down
2 changes: 2 additions & 0 deletions src/components/SearchForm/SearchForm.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { ChangeEvent, useState } from "react";
import { useRouter } from "next/router";
import { SearchBar, Box } from "@nypl/design-system-react-components";
import { SEARCH_BAR_TEST_ID } from "~/src/constants/testIds";
import { SearchQuery, SearchQueryDefaults } from "~/src/types/SearchQuery";
import { errorMessagesText, inputTerms } from "~/src/constants/labels";
import { toLocationQuery, toApiQuery } from "~/src/util/apiConversion";
Expand Down Expand Up @@ -89,6 +90,7 @@ const SearchForm: React.FC<{
onChange: (e) => onQueryChange(e),
}}
labelText="Search"
data-testid={SEARCH_BAR_TEST_ID}
/>
<Box float="right" marginTop={{ md: "xs" }}>
<Link to="/advanced-search" isUnderlined={false}>
Expand Down
4 changes: 4 additions & 0 deletions src/constants/testIds.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export const SEARCH_BAR_TEST_ID = "search-bar";
export const ERROR_LAYOUT_TEST_ID = "error-layout";
export const LOGIN_TO_READ_TEST_ID = "login-to-read";
export const LOGIN_TO_DOWNLOAD_TEST_ID = "login-to-download";
2 changes: 2 additions & 0 deletions src/pages/_error.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
Text,
} from "@nypl/design-system-react-components";
import { FeedbackContext } from "../context/FeedbackContext";
import { ERROR_LAYOUT_TEST_ID } from "../constants/testIds";

const ERROR_PERSISTS = " if the error persists.";

Expand Down Expand Up @@ -58,6 +59,7 @@ const Error = ({ statusCode }) => {
paddingRight="l"
textAlign="center"
role="alert"
data-testid={ERROR_LAYOUT_TEST_ID}
>
<Image
src="/images/error-img.png"
Expand Down

0 comments on commit 5556a42

Please sign in to comment.