Skip to content

Commit

Permalink
feat: automated a11y tests
Browse files Browse the repository at this point in the history
  • Loading branch information
miles-grant-ibigroup committed Aug 9, 2021
1 parent 8b1295d commit f0dbcb1
Show file tree
Hide file tree
Showing 11 changed files with 485 additions and 30 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/node-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ on:

jobs:
test-build-release:

runs-on: ubuntu-latest

steps:
Expand All @@ -29,6 +28,8 @@ jobs:
run: yarn jest
- name: Build example project
run: yarn build
- name: Run a11y tests
run: yarn a11y-test

# at this point, the build is successful
- name: Semantic Release
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ dist
# secrets. Ignore any versions of config.yml, except for example.
*config.yml
!example-config.yml
!test-config.yml
20 changes: 0 additions & 20 deletions __tests__/a11y.js

This file was deleted.

67 changes: 67 additions & 0 deletions a11y/a11y.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import fs from 'fs'
import path from 'path'

import puppeteer from 'puppeteer'
import execa from 'execa'

import { mockServer } from './mock-server'

const OTP_RR_CONFIG_FILE_PATH = './config.yml'
const OTP_RR_CONFIG_BACKUP_PATH = './config.non-test.yml'
const OTP_RR_TEST_CONFIG_PATH = './a11y/test-config.yml'

beforeEach(() => {
// backup current config file
if (fs.existsSync(OTP_RR_CONFIG_FILE_PATH)) {
fs.renameSync(
OTP_RR_CONFIG_FILE_PATH,
OTP_RR_CONFIG_BACKUP_PATH
)
console.log('Backed up current OTP-RR config file')
}
// copy over test config file
fs.copyFileSync(
OTP_RR_TEST_CONFIG_PATH,
OTP_RR_CONFIG_FILE_PATH
)
console.log('Copied a11y test config file')

// Build OTP-RR main.js using new config file
execa.sync('yarn', ['build'])
console.log('Built OTP-RR')

// Launch mock OTP server
const MOCK_SERVER_PORT = 9999
mockServer.listen(MOCK_SERVER_PORT, () => {
console.log(`Mock response server running on http://localhost:${MOCK_SERVER_PORT}`)
})
})

afterEach(() => {
fs.unlinkSync(OTP_RR_CONFIG_FILE_PATH)
if (fs.existsSync(OTP_RR_CONFIG_BACKUP_PATH)) {
fs.renameSync(
path.resolve(OTP_RR_CONFIG_BACKUP_PATH),
path.resolve(OTP_RR_CONFIG_FILE_PATH)
)
}
console.log('Restored original OTP-RR config file')
})

test('checks the test page with Axe', async () => {
jest.setTimeout(600000)
// Web security is disabled to allow requests to the mock OTP server
const browser = await puppeteer.launch({args: ['--disable-web-security']})
const page = await browser.newPage()
await page.goto(`file://${path.resolve(__dirname, '../index-for-puppeteer.html')}#/?ui_activeSearch=0qoydlnut&ui_activeItinerary=0&fromPlace=1900%20Main%20Street%2C%20Houston%2C%20TX%2C%20USA%3A%3A29.750144%2C-95.370998&toPlace=800%20Congress%2C%20Houston%2C%20TX%2C%20USA%3A%3A29.76263%2C-95.362178&date=2021-08-04&time=08%3A14&arriveBy=false&mode=WALK%2CBUS%2CTRAM&showIntermediateStops=true&maxWalkDistance=1207&optimize=QUICK&walkSpeed=1.34&ignoreRealtimeUpdates=true&numItineraries=3&otherThanPreferredRoutesPenalty=900`)

// These rules aren't relevant to this project
await expect(page).toPassAxeTests({
disabledRules: [
'region', // Leaflet does not comply
'meta-viewport', // Leaflet does not comply
'page-has-heading-one' // Heading is provided by logo
]
})
await browser.close()
})
18 changes: 18 additions & 0 deletions a11y/mock-server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
const express = require('express')

const PLAN_REALTIME = require('./mocks/plan.json')
const STOPS_FIRST = require('./mocks/stops.json')
const PARK_AND_RIDE = require('./mocks/pr.json')

const app = express()
// Mock exactly the requests the test link will create requests to
app.get('/otp/routers/default/plan', (req, res) => {
res.send(PLAN_REALTIME)
})
app.get('/otp/routers/default/index/stops', (req, res) => {
res.send(STOPS_FIRST)
})
app.get('/otp/routers/default/park_and_ride', (req, res) => {
res.send(PARK_AND_RIDE)
})
module.exports.mockServer = app
1 change: 1 addition & 0 deletions a11y/mocks/plan.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions a11y/mocks/pr.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[{"name":"P+R Eastwood Park & Ride","x":-95.33571105000001,"y":29.72878155},{"name":"P+R Magnolia Park & Ride","x":-95.30348190000001,"y":29.73431275},{"name":"P+R Eastex Park & Ride","x":-95.29903390000001,"y":29.927564550000003},{"name":"P+R Fifth Ward Park & Ride","x":-95.31554165,"y":29.776087200000003},{"name":"P+R Maxey Road Park & Ride","x":-95.2173539,"y":29.784856000000005},{"name":"P+R Kashmere Park & Ride","x":-95.32818135000001,"y":29.813871050000003},{"name":"P+R Cypress Park & Ride","x":-95.68538430000001,"y":29.964691300000002},{"name":"P+R Kuykendahl Park & Ride","x":-95.4254829,"y":29.973071000000004},{"name":"P+R Fuqua Park & Ride","x":-95.2169867,"y":29.60929745},{"name":"P+R Hilcroft Park and Ride","x":-95.4953988,"y":29.722077400000003},{"name":"P+R Kingsland Park & Ride","x":-95.74403235,"y":29.773826550000003},{"name":"P+R Bay Area Park and Ride","x":-95.1242302,"y":29.553318850000004},{"name":"P+R Spring Park and Ride","x":-95.41705290000002,"y":30.0219978},{"name":"P+R Grand Parkway Park & Ride","x":-95.775868,"y":29.787324400000003},{"name":"P+R Missouri City Park and Ride","x":-95.50684269999999,"y":29.62220885},{"name":"P+R Addicks Park and Ride","x":-95.6378214,"y":29.7871035},{"name":"P+R South Point Park & Ride","x":-95.2090594,"y":29.613153700000005},{"name":"P+R West Loop Park & Ride","x":-95.4590115,"y":29.67969695},{"name":"P+R West Loop Park & Ride","x":-95.4575754,"y":29.678453400000002},{"name":"P+R West Loop Park & RIde","x":-95.45893530000001,"y":29.680618600000003},{"name":"P+R West Loop Park & Ride","x":-95.45812955,"y":29.67963985},{"name":"P+R METRO West Bellfort Park & Ride","x":-95.56057320000001,"y":29.6551495},{"name":"P+R Townsen Park and Ride","x":-95.2639671,"y":30.019417250000004},{"name":"P+R Townsen Park and Ride","x":-95.2640864,"y":30.018127850000003},{"name":"P+R","x":-95.5108057,"y":29.53132745},{"name":"P+R Baytown Park & Ride","x":-94.9865383,"y":29.79922535},{"name":"P+R Northline Transit Center Parking","x":-95.3763821,"y":29.8326085},{"name":"P+R Westwood Park and Ride","x":-95.54868185000001,"y":29.672184450000003},{"name":"P+R Northwest Transit Center Park & Ride","x":-95.4537731,"y":29.78344215},{"name":"P+R","x":-95.4542179,"y":29.7830552},{"name":"P+R Westwood Park and Ride","x":-95.54843235000001,"y":29.672169000000004},{"name":"P+R Monroe Park and Ride","x":-95.25483990000001,"y":29.664887150000002},{"name":"P+R Kingsland Park & Ride","x":-95.7442418,"y":29.77444045},{"name":"P+R Hiram Clarke Park & Ride","x":-95.43183185000001,"y":29.614350900000005},{"name":"P+R Northwest Station Park & Ride","x":-95.59425515000001,"y":29.901728900000002},{"name":"P+R Seton Lake Park & Ride","x":-95.49940015,"y":29.927510500000004},{"name":"P+R West Little York Park & Ride","x":-95.55293265,"y":29.86934865},{"name":"P+R Kingwood Park and Ride","x":-95.1830843,"y":30.054689000000003},{"name":"P+R El Dorado Park & Ride","x":-95.1573459,"y":29.54807475},{"name":"P+R Mission Bend Transit Center","x":-95.6294207,"y":29.710549450000002},{"name":"P+R Gessner Park and Ride","x":-95.53812250000001,"y":29.720586000000004},{"name":"P+R Westchase Park and Ride","x":-95.5627122,"y":29.716845600000003},{"name":"P+R Southeast Park & Ride","x":-95.35762960000001,"y":29.7019081},{"name":"P+R Tidwell Park & Ride","x":-95.33732285,"y":29.852356300000004},{"name":"P+R North Shepherd Park & Ride","x":-95.41379545000001,"y":29.876002500000002},{"name":"P+R North Shepherd Park & Ride","x":-95.41460395000001,"y":29.877670450000004},{"name":"P+R North Shepherd Park & Ride","x":-95.41447335000001,"y":29.87597495},{"name":"P+R Fannin South Park & Ride","x":-95.40149275000002,"y":29.67472505},{"name":"P+R Conroe Park & Ride","x":-95.469595,"y":30.309220600000003}]
1 change: 1 addition & 0 deletions a11y/mocks/stops.json

Large diffs are not rendered by default.

168 changes: 168 additions & 0 deletions a11y/test-config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
branding: a11y-test
title: a11y test environment
homeTimezone: America/Chicago

# Default OTP API
api:
host: http://localhost:9999
# host: http://localhost:8001 # For testing against a local OTP instance
path: /otp/routers/default

# Enabled multimodal routing types (e.g. interary, profile)
routingTypes:
- key: ITINERARY
text: Exact Time

# Show/hide elevation profile chart for walk/bike legs
# elevationProfile: true

# Map config
map:
# Enabled map views
views:
- type: DEFAULT
text: Map View
# Delete/uncomment the following block to disable the stylized map
#- type: STYLIZED
# text: Network View

# Default map center
initLat: 29.7604
initLon: -95.3698
initZoom: 12

# Base layers for default map
baseLayers:
- name: Streets
url: //api.mapbox.com/styles/v1/mapbox/outdoors-v11/tiles/{z}/{x}/{y}{retina}?access_token=pk.eyJ1IjoiaWJpLXRyYW5zaXQtZGF0YS10ZWFtIiwiYSI6ImNqeTY3Zms2bzBkbjMzbGs5bWpoemRxY3UifQ.IrkMhr7JMhUNcb2qXuzwig
attribution: "© <a href='https://www.mapbox.com/about/maps/'>Mapbox</a> © <a href='http://www.openstreetmap.org/copyright'>OpenStreetMap</a> <strong><a href='https://www.mapbox.com/map-feedback/' target='_blank'>Improve this map</a></strong>"
maxZoom: 20
hasRetinaSupport: true
retina: "@2x"

overlays:
- type: bike-rental
name: BCycle Locations
modes:
- BICYCLE_RENT
companies:
- BCYCLE
mapSymbols:
- maxZoom: 12
minZoom: 0
type: circle
pixels: 3
fillColor: "#FF2E28"
dockStrokeColor: "#000000"
- maxZoom: 15
minZoom: 13
type: circle
pixels: 5
fillColor: "#FF2E28"
dockStrokeColor: "#000000"
- maxZoom: 20
minZoom: 16
fillColor: "#FF2E28"
dockStrokeColor: "#000000"
type: hubAndFloatingBike

- type: park-and-ride
name: Park & Ride Locations
maxTransitDistance: 1000
modes:
- CAR_PARK

- type: stops
name: Transit Stops
visible: true

geocoder:
# IBI geocode.earth proxy
baseUrl: https://cglx01n2ua.execute-api.us-east-1.amazonaws.com/prod
# Geocoding search bounds
boundary:
rect:
minLon: -97.4197
maxLon: -93.2674
minLat: 28.6093
maxLat: 30.9685
# fetch options
options:
headers:
# AWS API Gateway key specific to Houston (IBI AWS account):
# https://console.aws.amazon.com/apigateway/home?region=us-east-1#/api-keys/fchsdgyys9
x-api-key: lvJXqETokn3T338y1c8U843Fjh1ONdgzK3Ar0pl4
maxNearbyStops: 6
type: PELIAS

# A list of private transportation operators. These are either companies that
# provide rental vehicles or transportation network companies. Companies that
# have multiple modes of transport should have all modes listed as a string with
# commas. For example: BICYCLE_RENT,MICROMOBILITY_RENT.
companies:
- id: BCYCLE
label: BCycle
modes: BICYCLE_RENT

# Mode selector configuration
modes:
transitModes:
- mode: BUS
label: Bus
- mode: TRAM
label: METRORail

# access to transit modes. These options are all combined with the above
# transit modes in the request to OTP
accessModes:
- mode: BICYCLE
label: Transit + Personal bike
- mode: BICYCLE_RENT
label: Transit + BCycle
company: BCYCLE
- mode: CAR_PARK
label: Park & Ride
# which exclusive modes to show. This involves using a single mode and no
# transit for the duration of the trip. Further configurations of
# `bicycleModes`, `micromobilityModes` and/or `carModes` are needed as
# desired, but no extra configuration is needed for a WALK exclusive mode.
exclusiveModes:
- WALK
- BICYCLE

bicycleModes:
- mode: BICYCLE
label: Own Bike
iconWidth: 18
- mode: BICYCLE_RENT
label: BCycle
iconWidth: 36

errorMessages:
- id: 404
msg: Sorry, we couldn't find any transit or rideshare/carshare options at the time and/or location you chose. Please try again later, or change the settings of your trip.
modes:
- CAR_HAIL
- CAR_RENT
- id: 405
msg: Sorry, we couldn't find any transit or rideshare/carshare options at the time and/or location you chose. Please try again later, or change the settings of your trip.
modes:
- CAR_HAIL
- CAR_RENT
- id: 480
msg: No available transit routes or rideshare/carshare service at origin.

reportIssue:
mailto: [email protected]

# NOTE: Houston GA for production is set in the index.html file because it
# a new GA4 site tag that is not supported by react-ga:
# https://github.com/react-ga/react-ga/issues/460
# analytics:
# google:
# globalSiteTag: UA-XXXXXXX

dateTime:
timeFormat: h:mm a
dateFormat: MM/DD/YYYY
longDateFormat: MMMM D, YYYY
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
"description": "A library for writing modern OpenTripPlanner-compatible multimodal journey planning web applications using React and Redux",
"main": "build/index.js",
"scripts": {
"a11y-test": "mastarm test a11y --force-exit",
"build": "mastarm build --env production",
"cover": "mastarm test -e test --coverage",
"jest": "yarn build && mastarm test -e test",
"jest": "mastarm test -e test __tests__",
"lint": "mastarm lint lib __tests__ --quiet",
"lint-docs": "documentation lint lib/**/*.js",
"postinstall": "husky install",
Expand Down Expand Up @@ -117,6 +118,8 @@
"enzyme-adapter-react-16": "^1.4.0",
"enzyme-to-json": "^3.4.0",
"es6-math": "^1.0.0",
"execa": "^5.1.1",
"express": "^4.17.1",
"husky": "^6.0.0",
"leaflet": "^1.6.0",
"lint-staged": "^11.0.0",
Expand Down
Loading

0 comments on commit f0dbcb1

Please sign in to comment.