Skip to content

Commit

Permalink
Add PDF service in E2E (#8909)
Browse files Browse the repository at this point in the history
* test: Add PDF service in E2E

* test(e2e): change PDF approach to work with headless browsers
  • Loading branch information
Betree authored Dec 28, 2023
1 parent e32606f commit f1096f6
Show file tree
Hide file tree
Showing 18 changed files with 182 additions and 20 deletions.
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ env:
NODE_ENV: test
WEBSITE_URL: http://localhost:3000
API_URL: http://localhost:3060
PDF_SERVICE_URL: http://localhost:3002
API_KEY: dvl-1510egmf4a23d80342403fb599qd
CI: true

Expand Down
40 changes: 39 additions & 1 deletion .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@ env:
OC_ENV: ci
NODE_ENV: test
WEBSITE_URL: http://localhost:3000
IMAGES_URL: http://localhost:3001
PDF_SERVICE_URL: http://localhost:3002
API_URL: http://localhost:3060
API_KEY: dvl-1510egmf4a23d80342403fb599qd
CI: true

E2E_TEST: 1
PGHOST: localhost
PGUSER: postgres
IMAGES_URL: http://localhost:3001
CYPRESS_RECORD: false
CYPRESS_VIDEO: false
CYPRESS_VIDEO_UPLOAD_ON_PASSES: false
Expand All @@ -25,6 +26,7 @@ env:
FRONTEND_FOLDER: /home/runner/work/opencollective-frontend/opencollective-frontend
API_FOLDER: /home/runner/work/opencollective-frontend/opencollective-frontend/opencollective-api
IMAGES_FOLDER: /home/runner/work/opencollective-frontend/opencollective-frontend/opencollective-images
PDF_FOLDER: /home/runner/work/opencollective-frontend/opencollective-frontend/opencollective-pdf
TERM: xterm
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
STRIPE_WEBHOOK_KEY: ${{ secrets.STRIPE_WEBHOOK_KEY }}
Expand Down Expand Up @@ -129,6 +131,12 @@ jobs:
repository: opencollective/opencollective-images
path: opencollective-images

- name: Checkout (PDF)
uses: actions/checkout@v4
with:
repository: opencollective/opencollective-pdf
path: opencollective-pdf

# Prepare API

- name: Restore node_modules (api)
Expand Down Expand Up @@ -165,6 +173,24 @@ jobs:
working-directory: opencollective-images
run: npm run build

# Prepare PDF

- name: Restore node_modules (pdf)
uses: actions/cache@v3
id: pdf-node-modules
with:
path: opencollective-pdf/node_modules
key: ${{ runner.os }}-pdf-node-modules-${{ hashFiles('opencollective-pdf/package-lock.json') }}

- name: Install dependencies (pdf)
working-directory: opencollective-pdf
if: steps.pdf-node-modules.outputs.cache-hit != 'true'
run: npm ci --prefer-offline --no-audit

- name: Build (pdf)
working-directory: opencollective-pdf
run: npm run build

# Prepare Frontend

- name: Restore node_modules (frontend)
Expand Down Expand Up @@ -210,13 +236,18 @@ jobs:
if: steps.next-build.outputs.cache-hit != 'true'
run: npm run build

# Seed DB

- name: Setup DB
run: ./scripts/setup_db.sh

# Run tests

- name: Run E2E with Cypress
run: ./scripts/run_e2e_tests.sh
env:
CYPRESS_TEST_FILES: ${{ matrix.files }}

- name: Archive test recordings
uses: actions/upload-artifact@v3
with:
Expand All @@ -226,5 +257,12 @@ jobs:
test/cypress/videos
if: ${{ failure() }}

- name: Archive download folder
uses: actions/upload-artifact@v3
with:
name: downloads
path: test/cypress/downloads
if: ${{ failure() }}

- name: Report Coverage
run: npm run test:coverage
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ node_modules
npm-debug.log.*
./report.*.json
*.log
logs
yarn.lock
.DS_Store
build
coverage
.nyc_output
test/cypress/screenshots
test/cypress/videos
test/cypress/downloads
dist
stage
*.swp
Expand Down
11 changes: 9 additions & 2 deletions components/CreateGiftCardsSuccess.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export default class CreateGiftCardsSuccess extends React.Component {
};

renderManualSuccess() {
const filename = `${this.props.collectiveSlug}-giftcards-${Date.now()}.pdf`;
const filename = `${this.props.collectiveSlug}-giftcards.pdf`;
const downloadUrl = giftCardsDownloadUrl(filename);

return (
Expand Down Expand Up @@ -105,7 +105,14 @@ export default class CreateGiftCardsSuccess extends React.Component {
})}
>
{({ loading, downloadFile }) => (
<StyledButton minWidth={270} m={2} buttonSize="large" loading={loading} onClick={downloadFile}>
<StyledButton
minWidth={270}
m={2}
buttonSize="large"
loading={loading}
onClick={downloadFile}
data-cy="download-gift-cards-btn"
>
<Printer size="1em" />
&nbsp;
<FormattedMessage id="CreateGiftCardsSuccess.Download" defaultMessage="Download cards" />
Expand Down
1 change: 1 addition & 0 deletions components/expenses/ExpenseAttachedFiles.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const ExpenseAttachedFiles = ({ files, onRemove, openFileViewer }) => {
fileSize={file.info?.size}
showFileName
openFileViewer={openFileViewer}
data-cy="download-expense-invoice-btn"
/>
) : (
<LocalFilePreview size={88} file={file} />
Expand Down
1 change: 1 addition & 0 deletions components/expenses/ExpenseMoreActionsButton.js
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ const ExpenseMoreActionsButton = ({
loading={isLoading}
onClick={downloadInvoice}
disabled={processExpense.loading || isDisabled}
data-cy="download-expense-invoice-btn"
>
<IconDownload size="16px" />
{isLoading ? (
Expand Down
8 changes: 7 additions & 1 deletion components/transactions/TransactionDetails.js
Original file line number Diff line number Diff line change
Expand Up @@ -320,14 +320,20 @@ const TransactionDetails = ({ displayActions, transaction, onMutationSuccess })
{showDownloadInvoiceButton && (
<StyledButton
buttonSize="small"
data-loading={loadingInvoice}
loading={loadingInvoice}
onClick={downloadInvoiceWith({ transactionUuid: uuid, toCollectiveSlug: toAccount.slug })}
onClick={downloadInvoiceWith({
transactionUuid: uuid,
toCollectiveSlug: toAccount.slug,
createdAt: transaction.createdAt,
})}
minWidth={140}
background="transparent"
textTransform="capitalize"
ml={2}
mb={2}
px="unset"
data-cy="download-transaction-receipt-btn"
>
{expense && <FormattedMessage id="DownloadInvoice" defaultMessage="Download invoice" />}
{order && <FormattedMessage id="DownloadReceipt" defaultMessage="Download receipt" />}
Expand Down
3 changes: 3 additions & 0 deletions cypress.config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// eslint-disable-next-line node/no-unpublished-require
const { defineConfig } = require('cypress');
const fs = require('fs');
const { getTextFromPdfContent } = require('./test/cypress/scripts/get-text-from-pdf-content.ts');

module.exports = defineConfig({
experimentalMemoryManagement: true,
Expand All @@ -22,6 +23,7 @@ module.exports = defineConfig({
fixturesFolder: 'test/cypress/fixtures',
screenshotsFolder: 'test/cypress/screenshots',
videosFolder: 'test/cypress/videos',
downloadsFolder: 'test/cypress/downloads',
e2e: {
setupNodeEvents(on, config) {
// eslint-disable-next-line node/no-unpublished-require
Expand All @@ -39,6 +41,7 @@ module.exports = defineConfig({
console.log(...message); // eslint-disable-line no-console
return null;
},
getTextFromPdfContent,
});

// Delete videos if the test succeeds
Expand Down
4 changes: 2 additions & 2 deletions lib/transactions.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { formatCurrency } from './currency-utils';
import { toIsoDateStr } from './date-utils';
import { createError, ERROR } from './errors';
import { getFromLocalStorage, LOCAL_STORAGE_KEYS } from './local-storage';
import { collectiveInvoiceURL, invoiceServiceURL, transactionInvoiceURL } from './url-helpers';
import { collectiveInvoiceURL, PDF_SERVICE_URL, transactionInvoiceURL } from './url-helpers';

const messages = defineMessages({
hostFee: {
Expand Down Expand Up @@ -210,7 +210,7 @@ export const saveInvoice = async ({
dateTo,
createdAt,
});
const getParams = { format: 'blob', allowExternal: invoiceServiceURL };
const getParams = { format: 'blob', allowExternal: PDF_SERVICE_URL };
const accessToken = getFromLocalStorage(LOCAL_STORAGE_KEYS.ACCESS_TOKEN);
if (accessToken) {
getParams.headers = { Authorization: `Bearer ${accessToken}` };
Expand Down
10 changes: 5 additions & 5 deletions lib/url-helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { CollectiveType } from './constants/collectives';
import { TransactionTypes } from './constants/transactions';
import { getWebsiteUrl } from './utils';

export const invoiceServiceURL = process.env.PDF_SERVICE_URL;
export const PDF_SERVICE_URL = process.env.PDF_SERVICE_URL;

// ---- Utils ----

Expand Down Expand Up @@ -37,15 +37,15 @@ export const objectToQueryString = options => {
// ---- Routes to other Open Collective services ----

export const collectiveInvoiceURL = (collectiveSlug, hostSlug, startDate, endDate, format) => {
return `${invoiceServiceURL}/receipts/collectives/${collectiveSlug}/${hostSlug}/${startDate}/${endDate}/receipt.${format}`;
return `${PDF_SERVICE_URL}/receipts/collectives/${collectiveSlug}/${hostSlug}/${startDate}/${endDate}/receipt.${format}`;
};

export const transactionInvoiceURL = transactionUUID => {
return `${invoiceServiceURL}/receipts/transactions/${transactionUUID}/receipt.pdf`;
return `${PDF_SERVICE_URL}/receipts/transactions/${transactionUUID}/receipt.pdf`;
};

export const expenseInvoiceUrl = expenseId => {
return `${invoiceServiceURL}/expense/${expenseId}/invoice.pdf`;
return `${PDF_SERVICE_URL}/expense/${expenseId}/invoice.pdf`;
};

/**
Expand All @@ -54,7 +54,7 @@ export const expenseInvoiceUrl = expenseId => {
* @param {string} filename - filename **with** extension
*/
export const giftCardsDownloadUrl = filename => {
return `${invoiceServiceURL}/giftcards/from-data/${filename}`;
return `${PDF_SERVICE_URL}/giftcards/from-data/${filename}`;
};

// ---- Routes to external services ----
Expand Down
29 changes: 29 additions & 0 deletions package-lock.json

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

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@
"node-polyfill-webpack-plugin": "^3.0.0",
"npm-run-all": "^4.1.5",
"nyc": "^15.1.0",
"pdf-parse": "^1.1.1",
"postcss": "8.4.32",
"prettier": "3.1.1",
"prettier-plugin-tailwindcss": "0.5.9",
Expand Down
29 changes: 22 additions & 7 deletions scripts/run_e2e_tests.sh
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
#!/bin/bash

mkdir -p logs

echo "> Starting maildev server"
npx [email protected] &
MAILDEV_PID=$!

echo "> Starting stripe webhook listener"
export STRIPE_WEBHOOK_SIGNING_SECRET=$(stripe --api-key $STRIPE_WEBHOOK_KEY listen --forward-connect-to localhost:3060/webhooks/stripe --print-secret)
stripe --api-key $STRIPE_WEBHOOK_KEY listen --forward-connect-to localhost:3060/webhooks/stripe > /dev/null &
stripe --api-key $STRIPE_WEBHOOK_KEY listen --forward-connect-to localhost:3060/webhooks/stripe >/dev/null &
STRIPE_WEBHOOK_PID=$!

echo "> Starting api server"
Expand Down Expand Up @@ -35,10 +37,20 @@ if [ -z "$IMAGES_FOLDER" ]; then
else
cd $IMAGES_FOLDER
fi
npm start &
npm start >../logs/images-service.txt 2>&1 &
IMAGES_PID=$!
cd -

echo "> Starting PDF server"
if [ -z "$PDF_FOLDER" ]; then
cd ~/pdf
else
cd $PDF_FOLDER
fi
PORT=3002 npm start >../logs/pdf-service.txt 2>&1 &
PDF_PID=$!
cd -

# Set `$CYPRESS_RECORD` to `true` in ENV to activate records
if [ "$CYPRESS_RECORD" = "true" ]; then
CYPRESS_RECORD="--record"
Expand Down Expand Up @@ -71,6 +83,8 @@ echo ""
wait_for_service Frontend 127.0.0.1 3000
echo ""
wait_for_service IMAGES 127.0.0.1 3001
echo ""
wait_for_service PDF 127.0.0.1 3002

echo ""
echo "> Running cypress tests"
Expand All @@ -80,15 +94,16 @@ npm run cypress:run -- ${CYPRESS_RECORD} --env OC_ENV=$OC_ENV --spec "test/cypre
RETURN_CODE=$?
if [ $RETURN_CODE -ne 0 ]; then
echo "Error with cypress e2e tests, exiting"
exit 1;
exit 1
fi
echo ""

echo "Killing all node processes"
kill $MAILDEV_PID;
kill $MAILDEV_PID
kill $STRIPE_WEBHOOK_PID
kill $API_PID;
kill $FRONTEND_PID;
kill $IMAGES_PID;
kill $API_PID
kill $FRONTEND_PID
kill $IMAGES_PID
kill $PDF_PID
echo "Exiting with code $RETURN_CODE"
exit $RETURN_CODE
Loading

2 comments on commit f1096f6

@vercel
Copy link

@vercel vercel bot commented on f1096f6 Dec 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vercel
Copy link

@vercel vercel bot commented on f1096f6 Dec 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.