Skip to content

Commit

Permalink
v2.1 release (#368)
Browse files Browse the repository at this point in the history
* Add pagination through URL
* Add Cypress tests for pagination and URL parameter
* Add sorting option to the URL
* Add sort action in URL
* Fix pagination url
* Update README.md
* Remove robots.txt on production builds
* Remove GA on non production env
* Fixed node env fetching
* Added a buildspec for dev
* Fixed Tailwind Jit compiler to disable file watcher
* Preserve assets filenames
* Share button feature (#354)
* Add share button feature
* Close modal on failed clipboard writing
* Close box button
* Improve a11y
* Improve book card checks
* Remove toUppercase transform function
* Display H5P activity count on book cards & update test
* Invalidate cache in cloudfront after build (#363)
* Add recommended input attributes (#366)
  • Loading branch information
SteelWagstaff authored Jun 21, 2021
1 parent cdb49ad commit aeabfff
Show file tree
Hide file tree
Showing 58 changed files with 1,460 additions and 521 deletions.
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ VITE_ALGOLIA_INDEX_LAST_UPDATED_REPLICA=
VITE_HEADER_ADDITIONAL_TEXT=
VITE_HEADER_ADDITIONAL_TEXT=
VITE_USER_NODE_ENV=
VITE_APP_GA_MEASUREMENT_ID=
BROWSERSTACK_USERNAME=
BROWSERSTACK_ACCESS_KEY=
114 changes: 42 additions & 72 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,113 +1,83 @@
# Pressbooks Directory (Front End)
This Project is a Vue 3 vite project based on https://vitejs.dev/ and is backwards compatible with Vue 2.

## Environment variables setup
Create an `.env.local` file using the `.env.example` file: `cp .env.example .env.local`
and set the values for those variables for your local environments.

## Project setup

This Project is a Vue 3 vite project based on https://vitejs.dev/ is backwards compatible with Vue 2.

### Requirements
## Requirements

- Node.js version >=15.14.0.
- NPM version >=7.0.0

### Install dependencies
## Setup environment variables
Create an `.env.local` file using the `.env.example` file: `cp .env.example .env.local` and set appropriate values for those variables for your local environments.

## Customize configuration
See [Configuration Reference](https://vitejs.dev/).

## Install dependencies
```
npm install
```

### Compiles and hot-reloads for development
## Compile and hot-reload for development
```
npm run dev
```
app will run in port 3001

### Compiles and minifies for production
## Compile and minify for production
```
npm run build
```

### Lints and fixes files
## Lint and fix files
```
npm run lint
```

### Customize configuration

See [Configuration Reference](https://vitejs.dev/).
### Deployment
Deployment of this application is automatic once the dev or master branch is updated.
The pipeline uses AWS's CodePipeline to check periodically for changes in the github repository,
build assets using `npm run build`,
and puts the content in the 'dist' folder to the S3 bucket where it is hosted as a static website.

#### Environment Variables
All environment variables needed are set in the CodeBuild's environment variables.
To update an environment variable, go to the aws console in CodePipeline, select the pipeline, and
edit the 'Build' stage.
## Deployment
Deployment of this application is automatic once the dev or master branch is updated. The pipeline uses AWS's CodePipeline to check periodically for changes in the GitHub repository, build assets using `npm run build`, and puts the content in the 'dist' folder to the S3 bucket where it is hosted as a static website.

Then update the buildspec of the CodeBuild Project configuration in AWS.
### Environment Variables
All environment variables needed are set in the CodeBuild's environment variables. To update an environment variable, go to the AWS console in CodePipeline, select the pipeline, and edit the 'Build' stage. Then update the buildspec of the CodeBuild Project configuration in AWS.

ex: VITE_APP_ALGOLIA_APP_ID=${VITE_APP_ALGOLIA_APP_ID} NEW_ENV_VAR=${NEW_ENV_VAR_VALUE} npm run build

### SSL Certificates
SSL certificates use AWS's Certification Manager along with CloudFront
to ensure the application uses https. The certification is renewed automatically by AWS.

### Testing
We are using [Cypress](https://www.cypress.io/) with [BrowserStack](https://browserstack.com) for E2E testing, however you can use e2e tests locally as well.
Tests are located in `e2e/integration` folder.
#### Run E2E tests locally
SSL certificates use AWS's Certification Manager along with CloudFront to ensure the application uses https. The certification is renewed automatically by AWS.

1. You can run local tests on **Chrome**, **Firefox** and **Edge**. Make sure you have at least one of those browsers installed on your local machine.
1. We use `e2e_pressbooks_directory`, `e2e_pressbooks_sort_by_wordCount` and `e2e_pressbooks_directory_by_lastUpdated` Algolia indexes for run our tests.
Make sure you added those to your `.env` file:
```
VITE_ALGOLIA_INDEX=e2e_pressbooks_directory
VITE_ALGOLIA_INDEX_WORD_COUNT_REPLICA=e2e_pressbooks_sort_by_wordCount
VITE_ALGOLIA_INDEX_LAST_UPDATED_REPLICA=e2e_pressbooks_directory_by_lastUpdated
```
1. The local server should already be running: `npm run dev` before tests are run locally.
1. Tests can be run locally with the following command: `npm run test`. Cypress app will open, and you would choose in which browser do you want to run your tests
1. You can run E2E tests on headless mode by running: `npm run test:ci`
1. You also can run E2E tests on BrowserStack locally by running: `npm run test:stack` (make sure you have been defined `BROWSERSTACK_USERNAME` and `BROWSERSTACK_ACCESS_KEY` env variables. See next section for more details).
## Testing
We use [Cypress](https://www.cypress.io/) with [BrowserStack](https://browserstack.com) for E2E testing. Tests are located in `e2e/integration` folder. All tests will run against `e2e_pressbooks_directory` index. The Pressbooks Directory app must be properly configured with a working Algolia application and indices properly defined in the relevant environment variables.

#### Run E2E tests on BrowserStack
### Run E2E tests on BrowserStack
Make sure to declare your BrowserStack credentials in your `.env` file:
```
BROWSERSTACK_USERNAME=<YOUR BROWSERSTACK USERNAME>
BROWSERSTACK_ACCESS_KEY=<YOUR BROWSER STACK ACCESS KEY>
```
For more information see: https://www.browserstack.com/docs/automate/selenium/reset-access-key

Example: `npm run test:stack`.

Running only one spec file

Example: `npm run test:stack --specs=e2e/integration/pagination.spec.js`.

Make sure you declared your BrowserStack credentials in your `.env` file:
```
BROWSERSTACK_USERNAME=<YOUR BROWSERSTACK USERNAME>
BROWSERSTACK_ACCESS_KEY=<YOUR BROWSER STACK ACCESS KEY>
```
For more information see: https://www.browserstack.com/docs/automate/selenium/reset-access-key

All browser matrix is setup on: `browserstack.json`
The browser matrix can be configured locally in: `browserstack.json`

#### See tests Reports
If you run your tests on BrowserStack, you can see reports in [App Live BrowserStack Dashboard](https://automate.browserstack.com/dashboard/v2/).
BrowserStack reports can be accessed in [App Live BrowserStack Dashboard](https://automate.browserstack.com/dashboard/v2/).

### Algolia configuration
All tests will run against `e2e_pressbooks_directory` index
The Pressbooks Directory app must be properly configured with an Algolia application and index. See details [here](https://docs.google.com/document/d/1SNf7jIelkXwzzAxEbGSjEL59GMDeh3o3wH7myY3LfBM/edit#).
### Run E2E tests locally
Tests can also be run locally as well using the instructions below:
1. You can run local tests on **Chrome**, **Firefox** and **Edge**. Make sure you have at least one of those browsers installed on your local machine.
1. Make sure that you have properly configured the Algolia indices to be used by your application. The Pressbooks internal team can find details [here](https://docs.google.com/document/d/1SNf7jIelkXwzzAxEbGSjEL59GMDeh3o3wH7myY3LfBM/edit?usp=sharing)
1. The local server should already be running: `npm run dev` before tests are run locally.
1. Tests can be run locally with the following command: `npm run test`. Cypress app will open, and you would choose in which browser do you want to run your tests
1. You can run E2E tests on headless mode by running: `npm run test:ci`
1. You also can run E2E tests on BrowserStack locally by running: `npm run test:stack` (make sure you have been defined `BROWSERSTACK_USERNAME` and `BROWSERSTACK_ACCESS_KEY` env variables. See next section for more details).

### Google Analytics integration
In `public/index.html` file you can find the required script for Google Analytics.
If `VUE_APP_GA_MEASUREMENT_ID` environment variable defined, the Google Analytics script will be added.
In order to send data to google, only thing needed is to add the environment variable.
## Google Analytics integration
The required script for Google Analytics can be found in `public/index.html`. To send Google Analytics information, you must define `VITE_APP_GA_MEASUREMENT_ID` environment variable with a working Google Analytics ID.

### Sentry Integration
You can track errors and monitor performance with Sentry by defining the [Sentry DSN](https://docs.sentry.io/platforms/javascript/guides/vue/configuration/options/#dsn) in
`VITE_APP_SENTRY_DSN` environment variable. If this variable is defined, Sentry errors
and data performance will be sent to Sentry.
Defining `VITE_APP_SENTRY_TRACE_RATE` you can set the [Trace Sample Rate](https://docs.sentry.io/platforms/javascript/guides/vue/configuration/options/#tracesSampleRate) for tracing
the application in Sentry. If it is not defined, then the default value will be 0.5.
The environment value for Sentry is defined in `VITE_APP_ENVIRONMENT`, if this value is not defined, the default
value will be `development`.
## Sentry Integration
You can track errors and monitor performance with Sentry by defining the [Sentry DSN](https://docs.sentry.io/platforms/javascript/guides/vue/configuration/options/#dsn) in the `VITE_APP_SENTRY_DSN` environment variable. If this variable is defined, Sentry errors and data performance will be sent to Sentry.
You can set the [Trace Sample Rate](https://docs.sentry.io/platforms/javascript/guides/vue/configuration/options/#tracesSampleRate) by defining the `VITE_APP_SENTRY_TRACE_RATE` enviroment variable. If not defined, the default value will be 0.5.
You can define an environment value for Sentry through the `VITE_APP_ENVIRONMENT` environment variable. If not defined, the default value will be `development`.
3 changes: 3 additions & 0 deletions buildspec.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ phases:
build:
commands:
- npm run build
post_build:
commands:
- aws cloudfront create-invalidation --distribution-id $CLOUDFRONT_ID --paths '/*'
artifacts:
files:
- '**/*'
Expand Down
30 changes: 30 additions & 0 deletions buildspec_dev.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
version: 0.2
env:
shell: bash
phases:
install:
commands:
- rm -rf /etc/apt/sources.list.d/google-chrome.list
- echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections
- curl -fsSL https://deb.nodesource.com/setup_15.x | bash -
- apt-get update
- apt-get install nodejs -y -q
- mv /usr/local/bin/node /usr/local/bin/node14
- mv /usr/local/bin/npm /usr/local/bin/npm6
- mv /usr/bin/node /usr/local/bin/node
- npm install -g npm
- node -v
- npm -v
pre_build:
commands:
- npm install
build:
commands:
- npm run build:staging
post_build:
commands:
- aws cloudfront create-invalidation --distribution-id $CLOUDFRONT_ID --paths '/*'
artifacts:
files:
- '**/*'
base-directory: dist
1 change: 1 addition & 0 deletions e2e/fixtures/bookCard.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"title": "Significant Statistics",
"wordCount": "275135",
"size": "233.53",
"h5pActivities": "191",
"authors": "Adapted by John Morgan Russell, from Barbara Illowsky and Susan Dean, David Diez, Mine Cetinkaya-Rundel and Christopher D. Barr, Julie Vu and David Harrington",
"editors": "Anita Walz",
"subjects": "Probability and statistics",
Expand Down
6 changes: 5 additions & 1 deletion e2e/integration/bookCards.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ describe('Book cards', function () {
Elements.booksCards.cover,
Elements.booksCards.wordCount,
Elements.booksCards.size,
Elements.booksCards.h5pActivities,
Elements.booksCards.authors,
Elements.booksCards.lastUpdated,
Elements.booksCards.language,
Expand Down Expand Up @@ -82,7 +83,6 @@ describe('Book cards', function () {
search('Open Music Theory');
cy.get(Elements.booksCards.recommended)
.should('include.text', 'Recommended');

});
it('Check all book cards attributes from a particular book', () => {
const attributesToCheck = [
Expand All @@ -107,6 +107,10 @@ describe('Book cards', function () {
element: Elements.booksCards.size,
fixtureProperty: 'size'
},
{
element: Elements.booksCards.h5pActivities,
fixtureProperty: 'h5pActivities'
},
{
element: Elements.booksCards.authors,
fixtureProperty: 'authors'
Expand Down
45 changes: 35 additions & 10 deletions e2e/integration/filters/bookCardFilters.spec.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import Elements from '../../support/elements';

describe('BookCard Collections Filters',() => {
describe('BookCard Collections Filters', () => {
context('Desktop Resolution', () => {

it('Recommended filter toggle',()=>{
it('Recommended filter toggle', () => {

cy.get(Elements.booksCards.recommended).should('have.class','text-pb-red');

Expand All @@ -26,26 +26,51 @@ describe('BookCard Collections Filters',() => {

});

it('Collection filter toggle',()=>{
it('Collection filter toggle', () => {

cy.visit('/?collec=OpenStax');

cy.algoliaQueryRequest('algoliaRequest');

cy.get(Elements.booksCards.recommended+':nth-of-type(1)').next().should('have.class','text-pb-red');
cy.get(Elements.booksCards.recommended+':nth-of-type(1)').next().next().should('have.class','text-white');

cy.get(Elements.booksCards.recommended+':nth-of-type(1)').next().click();
cy.get(Elements.booksCards.recommended+':nth-of-type(1)')
.parent()
.next()
.find('button')
.should('have.class', 'text-pb-red');
cy.get(Elements.booksCards.recommended+':nth-of-type(1)')
.parent()
.next()
.next()
.find('button')
.should('have.class', 'text-white');

cy.get(Elements.booksCards.recommended+':nth-of-type(1)')
.parent()
.next()
.find('button')
.click();

cy.algoliaQueryRequest('algoliaRequest');

cy.get(Elements.booksCards.recommended+':nth-of-type(1)').next().should('have.class','text-white');
cy.get(Elements.booksCards.recommended+':nth-of-type(1)')
.parent()
.next()
.find('button')
.should('have.class', 'text-white');

cy.get(Elements.booksCards.recommended+':nth-of-type(1)').next().click();
cy.get(Elements.booksCards.recommended+':nth-of-type(1)')
.parent()
.next()
.find('button')
.click();

cy.algoliaQueryRequest('algoliaRequest');

cy.get(Elements.booksCards.recommended+':nth-of-type(1)').next().should('have.class','text-pb-red');
cy.get(Elements.booksCards.recommended+':nth-of-type(1)')
.parent()
.next()
.find('button')
.should('have.class', 'text-pb-red');

cy.url().should('include','?collec=OpenStax');

Expand Down
6 changes: 3 additions & 3 deletions e2e/integration/filters/filters.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ describe('Filters',() => {

cy.algoliaQueryRequest('algoliaRequest');

cy.get('article[data-cy=license-filter]').as('licenseAccordion')
.get('article[data-cy=subject-filter]').as('subjectAccordion');
cy.get('div[data-cy=license-filter]').as('licenseAccordion')
.get('div[data-cy=subject-filter]').as('subjectAccordion');

cy.get('@licenseAccordion').click()
.get('@subjectAccordion').click();
Expand All @@ -21,7 +21,7 @@ describe('Filters',() => {
.as('subjectSearch');

cy.get('@subjectAccordion')
.find('[data-cy=filter-about-option]:nth-child(2)') // It's the second one because we have the search as a child
.find('[data-cy=filter-about-option]:first-child')
.as('subjectFirstItem')
.find('span')
.should('contain.text', 'Education (97)');
Expand Down
21 changes: 15 additions & 6 deletions e2e/integration/filters/h5p.spec.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import {clickAccordionHeader, fillNumericValue, getNumericInput, submitNumericFilter} from '../../support/common';
import {
clickAccordionHeader,
encodeFacetFilterForURL,
fillNumericValue,
getNumericInput,
submitNumericFilter
} from '../../support/common';
import Elements from '../../support/elements';

describe('H5p Count Filters',() => {
Expand Down Expand Up @@ -123,20 +129,23 @@ describe('H5p Count Filters',() => {

submitNumericFilter('h5pActivities');

const min = getNumericInput('h5pActivities','min');
submitNumericFilter('h5pActivities');

min.invoke('prop', 'validationMessage')
.should('equal', 'Value must be greater than or equal to 0.');
const min = getNumericInput('h5pActivities','min');

cy.url()
.should('not.include', 'h5p=');

fillNumericValue('h5pActivities','max',-10);

submitNumericFilter('h5pActivities');

const max = getNumericInput('h5pActivities','max');

max.invoke('prop', 'validationMessage')
.should('equal', 'Value must be greater than or equal to 0.');
submitNumericFilter('h5pActivities');

cy.url()
.should('not.include', 'h5p=');

fillNumericValue('h5pActivities','min',100);
fillNumericValue('h5pActivities','max',6);
Expand Down
Loading

0 comments on commit aeabfff

Please sign in to comment.