From 56e7b692b1ad55d1cd9cf6c6696485cb4d3a02f7 Mon Sep 17 00:00:00 2001 From: Stephanie Honore Date: Mon, 29 Aug 2022 12:55:10 -0500 Subject: [PATCH] feat(component): repairing unit tests and adding pre-commit hook back --- .husky/pre-commit | 2 +- babel.config.js | 9 +-- commitlint.config.js | 18 +++++- packageScripts/postinstall.js | 5 +- rollup.config.js | 7 ++- scripts/generateDocs.js | 107 ++++++++++++++++++++------------ scripts/postCss.js | 46 ++++++++------ scripts/pre-commit.js | 5 +- scripts/prepForBuild.js | 16 +++-- src/auro-flight-header.js | 33 +++++----- src/auro-flight-main.js | 87 ++++++++++++++------------ src/auro-flight.js | 25 ++++---- src/style-flight-main.scss | 4 +- test/auro-flight-header.test.js | 4 +- test/auro-flight-main.test.js | 2 +- 15 files changed, 211 insertions(+), 159 deletions(-) diff --git a/.husky/pre-commit b/.husky/pre-commit index aec6154..2ff188e 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,4 +1,4 @@ #!/bin/sh . "$(dirname "$0")/_/husky.sh" - +# ./node_modules/.bin/npm-run-all preCommit test linters postinstall \ No newline at end of file diff --git a/babel.config.js b/babel.config.js index 3c6f163..7bdd1ed 100644 --- a/babel.config.js +++ b/babel.config.js @@ -1,8 +1,6 @@ const { browserslist: defaultBrowserslist } = require('./package.json'); -const modernBrowserslist = defaultBrowserslist.filter( - (browser) => browser !== 'ie 11' -); +const modernBrowserslist = defaultBrowserslist.filter((browser) => browser !== 'ie 11'); const sharedPlugins = [ '@babel/plugin-syntax-dynamic-import', @@ -23,7 +21,10 @@ module.exports = { env: { modern: { // lit-element supports the last two versions of modern browsers, so we don't need to polyfill - exclude: ['node_modules/lit-element/**', 'node_modules/lit-html/**'], + exclude: [ + 'node_modules/lit-element/**', + 'node_modules/lit-html/**' + ], presets: [ [ '@babel/preset-env', diff --git a/commitlint.config.js b/commitlint.config.js index ecca7da..802cf46 100644 --- a/commitlint.config.js +++ b/commitlint.config.js @@ -1,8 +1,20 @@ module.exports = { extends: ['@commitlint/config-conventional'], rules: { - 'body-max-line-length': [0, 'always', 120], - 'footer-max-line-length': [0, 'always', 120], - 'header-max-length': [0, 'always', 120], + 'body-max-line-length': [ + 0, + 'always', + 120 + ], + 'footer-max-line-length': [ + 0, + 'always', + 120 + ], + 'header-max-length': [ + 0, + 'always', + 120 + ], }, }; diff --git a/packageScripts/postinstall.js b/packageScripts/postinstall.js index 19c25d9..fc3b670 100644 --- a/packageScripts/postinstall.js +++ b/packageScripts/postinstall.js @@ -1,4 +1,4 @@ -'use strict'; + const chalk = require('chalk'); const pjson = require('../package.json'); @@ -22,5 +22,4 @@ console.log(chalk.hex('#f26135')(` of `) + chalk.hex('#ffd200').bold(`auro-flight v${pjson.version}.`) + chalk.hex('#f26135')(` ╰─────────────────────────────── ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╯ -`) -); +`)); diff --git a/rollup.config.js b/rollup.config.js index 203847b..42e97ef 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -11,7 +11,10 @@ const production = !process.env.ROLLUP_WATCH; const getSharedPlugins = (isLegacy) => [ resolve({ // in case of multiple lit-element versions (e.g. importing another auro component) - dedupe: ['lit-element', 'lit-html'] + dedupe: [ + 'lit-element', + 'lit-html' + ] }), commonjs(), // skipPreflightCheck flag needed or else build fails @@ -60,4 +63,4 @@ const legacyConfig = { plugins: getSharedPlugins(true) }; -export default [modernConfig]; \ No newline at end of file +export default [modernConfig]; diff --git a/scripts/generateDocs.js b/scripts/generateDocs.js index fc0bdad..fb639fe 100644 --- a/scripts/generateDocs.js +++ b/scripts/generateDocs.js @@ -6,26 +6,29 @@ const https = require('https'); const readmeTemplateUrl = 'https://raw.githubusercontent.com/AlaskaAirlines/WC-Generator/master/componentDocs/README.md'; const dirDocTemplates = './docTemplates'; -const readmeFilePath = dirDocTemplates + '/README.md'; +const readmeFilePath = `${dirDocTemplates}/README.md`; /** - * Extract NPM, NAMESPACE and NAME from package.json + * Extract NPM, NAMESPACE and NAME from package.json. */ - function nameExtraction() { - const packageJson = fs.readFileSync('package.json', 'utf8', function(err, data) { +/** + * + */ +function nameExtraction() { + const packageJson = fs.readFileSync('package.json', 'utf8', (err, data) => { if (err) { console.log(chalk.red('ERROR: Unable to read package.json file', err)); } - }) + }); pName = JSON.parse(packageJson).name; - let npmStart = pName.indexOf('@'); - let namespaceStart = pName.indexOf('/'); - let nameStart = pName.indexOf('-'); + const npmStart = pName.indexOf('@'); + const namespaceStart = pName.indexOf('/'); + const nameStart = pName.indexOf('-'); - let result = { + const result = { 'npm': pName.substring(npmStart, namespaceStart), 'namespace': pName.substring(namespaceStart + 1, nameStart), 'namespaceCap': pName.substring(namespaceStart + 1)[0].toUpperCase() + pName.substring(namespaceStart + 2, nameStart), @@ -34,18 +37,21 @@ const readmeFilePath = dirDocTemplates + '/README.md'; }; return result; -}; +} /** - * Replace all instances of [npm], [name], [Name], [namespace] and [Namespace] accordingly + * Replace all instances of [npm], [name], [Name], [namespace] and [Namespace] accordingly. */ +/** + * + */ function formatTemplateFileContents(content, destination) { - let nameExtractionData = nameExtraction(); + const nameExtractionData = nameExtraction(); let result = content; /** - * Replace placeholder strings + * Replace placeholder strings. */ result = result.replace(/\[npm]/g, nameExtractionData.npm); result = result.replace(/\[name]/g, nameExtractionData.name); @@ -54,7 +60,7 @@ function formatTemplateFileContents(content, destination) { result = result.replace(/\[Namespace]/g, nameExtractionData.namespaceCap); /** - * Cleanup line breaks + * Cleanup line breaks. */ result = result.replace(/(\r\n|\r|\n)[\s]+(\r\n|\r|\n)/g, '\r\n\r\n'); // Replace lines containing only whitespace with a carriage return. result = result.replace(/>(\r\n|\r|\n){2,}/g, '>\r\n'); // Remove empty lines directly after a closing html tag. @@ -63,35 +69,41 @@ function formatTemplateFileContents(content, destination) { result = result.replace(/([^(\r\n|\r|\n)])(\r\n|\r|\n)+#/g, "$1\r\n\r\n#"); // Ensure empty line before header sections. /** - * Write the result to the destination file + * Write the result to the destination file. */ fs.writeFileSync(destination, result, { encoding: 'utf8'}); -}; +} +/** + * + */ function formatApiTableContents(content, destination) { const nameExtractionData = nameExtraction(); - const wcName = nameExtractionData.namespace + '-' + nameExtractionData.name; + const wcName = `${nameExtractionData.namespace}-${nameExtractionData.name}`; let result = content; - result = result - .replace(/\r\n|\r|\n####\s`([a-zA-Z]*)`/g, `\r\n#### \`$1\`back to top`) - .replace(/\r\n|\r|\n\|\s`([a-zA-Z]*)`/g, '\r\n| [$1](#$1)') - .replace(/\| \[\]\(#\)/g, ""); + result = result. + replace(/\r\n|\r|\n####\s`([a-zA-Z]*)`/g, `\r\n#### \`$1\`back to top`). + replace(/\r\n|\r|\n\|\s`([a-zA-Z]*)`/g, '\r\n| [$1](#$1)'). + replace(/\| \[\]\(#\)/g, ""); fs.writeFileSync(destination, result, { encoding: 'utf8'}); - fs.readFile('./demo/apiExamples.md', 'utf8', function(err, data) { + fs.readFile('./demo/apiExamples.md', 'utf8', (err, data) => { formatTemplateFileContents(data, './demo/apiExamples.md'); }); } /** - * If auroLabs project, include auroLabs documentation in `./README.md` + * If auroLabs project, include auroLabs documentation in `./README.md`. */ +/** + * + */ function processLabsReadmeContent() { - let nameExtractionData = nameExtraction(); + const nameExtractionData = nameExtraction(); if (nameExtractionData.npm === '@aurolabs') { const callbackAurolabs = function(updatedContent, outputConfig) { @@ -109,15 +121,18 @@ function processLabsReadmeContent() { } /** - * Compiles `./docTemplates/README.md` -> `./README.md` + * Compiles `./docTemplates/README.md` -> `./README.md`. */ +/** + * + */ function processReadme() { const callback = function(updatedContent, outputConfig) { - processLabsReadmeContent() + processLabsReadmeContent(); if (fs.existsSync('./README.md')) { - fs.readFile('./README.md', 'utf8', function(err, data) { + fs.readFile('./README.md', 'utf8', (err, data) => { formatTemplateFileContents(data, './README.md'); }); } else { @@ -138,13 +153,16 @@ function processReadme() { } /** - * Compiles `./docTemplates/demo.md` -> `./demo/demo.md` + * Compiles `./docTemplates/demo.md` -> `./demo/demo.md`. */ +/** + * + */ function processDemo() { const callback = function(updatedContent, outputConfig) { if (fs.existsSync('./demo/demo.md')) { - fs.readFile('./demo/demo.md', 'utf8', function(err, data) { + fs.readFile('./demo/demo.md', 'utf8', (err, data) => { formatTemplateFileContents(data, './demo/demo.md'); }); } else { @@ -162,11 +180,14 @@ function processDemo() { markdownMagic(markdownPath, configDemo, callback); } +/** + * + */ function processDot() { const callback = function(updatedContent, outputConfig) { if (fs.existsSync('./demo/dotCompliance.md')) { - fs.readFile('./demo/dotCompliance.md', 'utf8', function(err, data) { + fs.readFile('./demo/dotCompliance.md', 'utf8', (err, data) => { formatTemplateFileContents(data, './demo/dotCompliance.md'); }); } else { @@ -185,13 +206,16 @@ function processDot() { } /** - * Compiles `./docTemplates/apiExamples.md` -> `./demo/apiExamples.md` + * Compiles `./docTemplates/apiExamples.md` -> `./demo/apiExamples.md`. */ +/** + * + */ function processApiExamples() { const callback = function(updatedContent, outputConfig) { if (fs.existsSync('./demo/apiExamples.md')) { - fs.readFile('./demo/apiExamples.md', 'utf8', function(err, data) { + fs.readFile('./demo/apiExamples.md', 'utf8', (err, data) => { formatApiTableContents(data, './demo/apiExamples.md'); }); } else { @@ -210,25 +234,28 @@ function processApiExamples() { } /** - * Copy README.md template from static source - * */ + * Copy README.md template from static source. + */ +/** + * + */ function copyReadmeLocally() { - if (!fs.existsSync(dirDocTemplates)){ + if (!fs.existsSync(dirDocTemplates)) { fs.mkdirSync(dirDocTemplates); } if (!fs.existsSync(readmeFilePath)) { - fs.writeFile(readmeFilePath, '', function(err) { - if(err) { + fs.writeFile(readmeFilePath, '', (err) => { + if (err) { console.log(chalk.red('ERROR: Unable to create README.md file.', err)); } }); } - https.get(readmeTemplateUrl, function(response) { - let writeTemplate = response.pipe(fs.createWriteStream(readmeFilePath)); + https.get(readmeTemplateUrl, (response) => { + const writeTemplate = response.pipe(fs.createWriteStream(readmeFilePath)); writeTemplate.on('finish', () => { processReadme(); @@ -240,7 +267,7 @@ function copyReadmeLocally() { } /** - * Run all the actual document generation + * Run all the actual document generation. */ copyReadmeLocally(); processDemo(); diff --git a/scripts/postCss.js b/scripts/postCss.js index 0335036..879975a 100644 --- a/scripts/postCss.js +++ b/scripts/postCss.js @@ -7,15 +7,15 @@ const fs = require('fs'); const directoryPath = path.join(__dirname, '../src'); /** - * Default postCSS run + * Default postCSS run. */ -fs.readdir(directoryPath, function (err, files) { - //handling error +fs.readdir(directoryPath, (err, files) => { + // handling error if (err) { - return console.log('Unable to scan directory: ' + err); + return console.log(`Unable to scan directory: ${err}`); } - //listing all files using forEach - files.forEach(function (file) { + // listing all files using forEach + files.forEach((file) => { if (file.includes(".css")) { standardProcessor(file); } @@ -27,20 +27,26 @@ fs.readdir(directoryPath, function (err, files) { * and completes a post cleanup. * @param {string} file */ - function standardProcessor(file) { +function standardProcessor(file) { fs.readFile(`src/${file}`, (err, css) => { - postcss([autoprefixer, comments]) - .use(comments({ - remove: function(comment) { return comment[0] == "@"; } - })) - .use(removeRules({ - rulesToRemove: { - ':root': '*' - } - })) - .process(css, { from: `src/${file}`, to: `src/${file}` }) - .then(result => { - fs.writeFile(`src/${file}`, result.css, () => true) - }) + postcss([ + autoprefixer, + comments + ]). + use(comments({ + remove(comment) { + return comment[0] == "@"; + } + })). + use(removeRules({ + rulesToRemove: { + ':root': '*' + } + })). + process(css, { from: `src/${file}`, + to: `src/${file}` }). + then((result) => { + fs.writeFile(`src/${file}`, result.css, () => true); + }); }); } diff --git a/scripts/pre-commit.js b/scripts/pre-commit.js index cbd42cc..60fc37b 100644 --- a/scripts/pre-commit.js +++ b/scripts/pre-commit.js @@ -1,4 +1,4 @@ -'use strict'; + const chalk = require('chalk'); console.log(chalk.hex('#ffd200')(` @@ -13,5 +13,4 @@ console.log(chalk.hex('#ffd200')(` to ensure that you are compliant.`) + chalk.hex('#ffd200')(` ╰─────────────────────────────── ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╯ -`) -); +`)); diff --git a/scripts/prepForBuild.js b/scripts/prepForBuild.js index d235d83..cc7c56c 100644 --- a/scripts/prepForBuild.js +++ b/scripts/prepForBuild.js @@ -3,15 +3,17 @@ const bundle = 'auro-flight__bundled.js'; const indexFile = './build/index.html'; // File destination.txt will be created or overwritten by default. -let copyFiles = async function() { +const copyFiles = async function() { fs.copyFile(`./dist/${bundle}`, `./build/${bundle}`, (err) => { - if (err) throw err; + if (err) { + throw err; + } console.log(`${bundle} was copied to ./build dir`); }); -} +}; // Edit string in new index.html file -fs.readFile(indexFile, 'utf8', function (err,data) { +fs.readFile(indexFile, 'utf8', (err, data) => { copyFiles(); if (err) { @@ -20,7 +22,9 @@ fs.readFile(indexFile, 'utf8', function (err,data) { const element = data.replace(`../src/auro-flight.js`, `auro-flight__bundled.js`); - fs.writeFile(indexFile, element, 'utf8', function (err) { - if (err) return console.log(err); + fs.writeFile(indexFile, element, 'utf8', (err) => { + if (err) { + return console.log(err); + } }); }); diff --git a/src/auro-flight-header.js b/src/auro-flight-header.js index e52ac6f..5bcd30b 100644 --- a/src/auro-flight-header.js +++ b/src/auro-flight-header.js @@ -12,18 +12,14 @@ import styleCss from "./style-flight-header-css.js"; // See https://git.io/JJ6SJ for "How to document your components using JSDoc" /** - * auro-flight-header displays airline, duration, and day change information + * Auro-flight-header displays airline, duration, and day change information. * * @attr {Array} flights - Array of flight numbers `['AS 123', 'EK 432']` * @attr {String} duration - String for the duration. `1h 23m` - * @attr {Number} daysChanged - Number of days changed due to flight duration and timezone. Positive whole integer + * @attr {Number} daysChanged - Number of days changed due to flight duration and timezone. Positive whole integer. */ -// build the component class - class AuroFlightHeader extends LitElement { - - // function to define props used within the scope of this component static get properties() { return { flights: { type: Array }, @@ -42,8 +38,9 @@ class AuroFlightHeader extends LitElement { } /** - * @private Internal function to render either the flight number OR 'Multiple flights' - * @returns {String} Parsed airline code output + * Internal function to render either the flight number OR 'Multiple flights'. + * @private + * @returns {String} Parsed airline code output. */ flightType() { switch (this.flights.length) { @@ -59,14 +56,14 @@ class AuroFlightHeader extends LitElement { /** * Internal function to render the day change notification. * @private - * @returns {String} item to display + * @returns {String} Item to display. */ - flightDuration() { + flightDuration() { const dayDiff = new Date(this.arrivalTime).getUTCDay() - new Date(this.departureTime).getUTCDay(); return dayDiff > 0 ? html`+${dayDiff} day${dayDiff > 1 ? 's' : ''}` - : html`` + : html``; } readFlight(flight) { @@ -75,13 +72,13 @@ class AuroFlightHeader extends LitElement { /** * @private - * @returns composed screen reader summary - */ - composeScreenReaderSummary(){ + * @returns Composed screen reader summary. + */ + composeScreenReaderSummary() { return html` - ${this.flightType().includes('flights') ? - this.flightType() : - `Flight ${this.readFlight(this.flightType())}` + ${this.flightType().includes('flights') + ? this.flightType() + : `Flight ${this.readFlight(this.flightType())}` }, Duration: ${this.duration} `; @@ -108,4 +105,4 @@ class AuroFlightHeader extends LitElement { // define the name of the custom component if (!customElements.get("auro-flight-header")) { customElements.define("auro-flight-header", AuroFlightHeader); -} \ No newline at end of file +} diff --git a/src/auro-flight-main.js b/src/auro-flight-main.js index 11dfa46..1150d4d 100644 --- a/src/auro-flight-main.js +++ b/src/auro-flight-main.js @@ -11,16 +11,16 @@ import "focus-visible/dist/focus-visible.min.js"; import styleCss from "./style-flight-main-css.js"; // See https://git.io/JJ6SJ for "How to document your components using JSDoc" -/** - * auro-flight-main renders the middle 'frame' of the auro-flight component with the auro-flightline +/** . + * Auro-flight-main renders the middle 'frame' of the auro-flight component with the auro-flightline * DoT: STATION SIZE AND COLOR MUST BE IDENTICAL TO DISCLOSURE SIZE AND COLOR! * * @attr {String} arrivalTime - Time of arrival, e.g. `9:06 pm` - * @attr {String} arrivalStation - Station of arrival, e.g. `SEA` + * @attr {String} arrivalStation - (Updated) Station of arrival, e.g. `SEA` * @attr {String} departureTime - Time of departure, e.g. `5:36 am` - * @attr {String} departureStation - Station of departure, e.g. `PVD` - * @attr {String} reroutedDepartureStation - Station of rerouted departure, e.g. `PDX` - * @attr {String} reroutedArrivalStation - Station of rerouted arrival, e.g. `AVP` + * @attr {String} departureStation - (Updated) Station of departure, e.g. `PVD` + * @attr {String} reroutedDepartureStation - Station of rerouted (original departure station) departure, e.g. `PDX` + * @attr {String} reroutedArrivalStation - Station of rerouted (original arrival station) arrival, e.g. `AVP` * @attr {Array} stops - Flight segment list that includes duration and departure station, and if it is a stop over * @slot default - anticipates `` instances */ @@ -28,11 +28,6 @@ import styleCss from "./style-flight-main-css.js"; // build the component class class AuroFlightMain extends LitElement { - // constructor() { - // super(); - // } - - connectedCallback() { super.connectedCallback(); @@ -45,12 +40,16 @@ class AuroFlightMain extends LitElement { timeZone: this.timeZone }; + if(!this.stops){ + this.stops = []; + } + this.template = {}; } /** * @private - * @param {*string} time + * @param {*string} time String representation of time to convert to localized time string ex: 5am. * @returns Localized time based from UTC string. */ convertTime(time) { @@ -59,7 +58,7 @@ class AuroFlightMain extends LitElement { this.timeTemplate.timeZone = 'UTC'; newTime = new Date(time); - let localizedTime = newTime.toLocaleString('en-us', this.timeTemplate).replace(/^0+/u, ''); + const localizedTime = newTime.toLocaleString('en-us', this.timeTemplate).replace(/^0+/u, ''); return localizedTime; } @@ -67,9 +66,9 @@ class AuroFlightMain extends LitElement { /** * @private - * @param {string} station - * @returns mutated string - */ + * @param {string} station Airport code ex: SEA. + * @returns Mutated string. + */ readStation(station) { return Array.from(station).join(' '); } @@ -96,41 +95,47 @@ class AuroFlightMain extends LitElement { } /** -* @private -* @returns composed screen reader summary -*/ + * @param {number} idx A numbered index correlated to current stop. + * @private + * @returns A comma string or an empty string. + */ + addComma(idx) { + return idx === this.stops.length - 1 ? "" : ","; + } + + /** + * @private + * @returns Composed screen reader summary. + */ composeScreenReaderSummary() { - const isNotNonstop = !!this.stops; + const isNotNonstop = Boolean(this.stops); const dayDiff = new Date(this.arrivalTime).getUTCDay() - new Date(this.departureTime).getUTCDay(); - const layoverStopoverStringArray = this.stops?.length > 0 ? this.stops?.map((segment, idx) => { - return html` - with a ${segment.isStopover ? "stop" : "layover"} in ${segment.arrivalStation} ${segment.duration ? `for ${segment.duration}` : ""} ${idx === this.stops.length - 2 ? "and" - : idx === this.stops.length - 1 ? "" : "," - }` - }) : "" + const daysFromDeparture = dayDiff === 1 ? " next day" : ` ${dayDiff} days later`; + const secondToLastIndex = 2; + const layoverStopoverStringArray = this.stops.length > 0 ? this.stops.map((segment, idx) => html` + with a ${segment.isStopover ? "stop" : "layover"} in ${segment.arrivalStation} + ${segment.duration ? `for ${segment.duration}` : ""} + ${idx === this.stops.length - secondToLastIndex ? "and" : this.addComma(idx)}`) + : ""; + return html` - ${this.reroutedDepartureStation === 'undefined' ? - `Departs from ${this.readStation(this.departureStation)} + ${this.reroutedDepartureStation === 'undefined' + ? `Departs from ${this.readStation(this.departureStation)} at ${this.convertTime(this.departureTime)}, arrives ${this.readStation(this.arrivalStation)} - at ${this.convertTime(this.arrivalTime)}` : - `Flight ${this.readStation(this.reroutedDepartureStation)} to + at ${this.convertTime(this.arrivalTime)}` + : `Flight ${this.readStation(this.reroutedDepartureStation)} to ${this.readStation(this.reroutedArrivalStation)} has been re-routed. The flight now departs from ${this.readStation(this.departureStation)} at ${this.convertTime(this.departureTime)}, and arrives ${this.readStation(this.arrivalStation)} at ${this.convertTime(this.arrivalTime)} `} - ${dayDiff > 0 ? dayDiff === 1 ? " next day" : ` ${dayDiff} days later` : ""} + ${dayDiff > 0 ? daysFromDeparture : ""} ${isNotNonstop ? layoverStopoverStringArray : ", nonstop"}. - `; } - //the answer in both cases will be 3 - - // Maintain content polarity between text read by screen reader and visual content. render() { - // ${this.reroutedDepartureStation !== 'undefined' ? `Flight ${this.readStation(this.reroutedDepartureStation)} to ${this.readStation(this.reroutedArrivalStation)} has been re-routed.` : ''} return html`