Skip to content

Commit

Permalink
Merge branch 'development' of https://github.com/NYPL/sfr-bookfinder-…
Browse files Browse the repository at this point in the history
…front-end into NOREF_prepare-0.18.6-production
  • Loading branch information
kylevillegas93 committed Oct 28, 2024
2 parents e08c504 + 43802e8 commit efd53ca
Show file tree
Hide file tree
Showing 21 changed files with 106 additions and 133 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/
46 changes: 27 additions & 19 deletions .github/workflows/Playwright.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
name: Playwright Tests for Digital Research Books

on:
schedule:
- cron: "00 14 * * 1-5"
pull_request:
branches: [production]
types: [opened, synchronize, reopened]
# TODO: Remove https://drb-api-qa.nypl.org from behind the VPC
# on:
# pull_request:

jobs:
tests:
Expand All @@ -19,23 +16,34 @@ jobs:
with:
node-version-file: ".nvmrc"

- name: Install Docker
uses: docker/setup-buildx-action@v2
- name: Install Test Dependencies
run: npm i @cucumber/[email protected] @playwright/[email protected]

- name: Build and Run Docker Compose
run: |
docker-compose up -d
working-directory: ./sfr-bookfinder-front-end
- name: Install Playwright
run: npx playwright install --with-deps

- name: Update /etc/hosts
run: |
echo "127.0.0.1 local.nypl.org" | sudo tee -a /etc/hosts
- name: Build app
run: NODE_ENV=test npm run build

- name: Install Deps
run: npm i @cucumber/[email protected] @playwright/[email protected]
- name: Start the app
run: npm run dev &
shell: bash

- name: Install Playwright Browser Utils
run: npx playwright install --with-deps
- 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: Set the world parameters as an env var
# WORLD_PARAMETERS set here will override anything set in cucumber.json
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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# CHANGE LOG

## [Prerelease]

## [0.18.6]
- 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
1 change: 1 addition & 0 deletions act
Submodule act added at ccd28e
2 changes: 1 addition & 1 deletion cucumber.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"default": {
"import": ["playwright/tests/**/*.ts", "playwright/support/**/*.ts"],
"worldParameters": {
"appUrl": "http://localhost:3000",
"appUrl": "http://localhost:3000/",
"headless": false
}
}
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";
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "sfr-bookfinder-front-end",
"version": "0.18.5",
"version": "0.18.6",
"private": true,
"scripts": {
"dev": "next dev",
Expand Down
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";
Loading

0 comments on commit efd53ca

Please sign in to comment.