diff --git a/app.js b/app.js index b642ee9..e49b6b7 100755 --- a/app.js +++ b/app.js @@ -1,54 +1,55 @@ // import environment variables. -require('dotenv').config() -const globalError = require('http-errors') +require("dotenv").config(); +const globalError = require("http-errors"); // import node modules. -const express = require('express'), - cookieParser = require('cookie-parser'), - compression = require('compression'), - helmet = require('helmet'), - morgan = require('morgan'), - winston = require('./config/winston.config'), - sassMiddleware = require('node-sass-middleware'), - path = require('path'), - cookieSession = require('cookie-session'), - cookieSessionConfig = require('./config/cookieSession.config'), - { SINFilter, hasData, checkPublic, sortByLineNumber, checkLangQuery, currencyFilter } = require('./utils') +const express = require("express"), + cookieParser = require("cookie-parser"), + compression = require("compression"), + helmet = require("helmet"), + morgan = require("morgan"), + winston = require("./config/winston.config"), + sassMiddleware = require("node-sass-middleware"), + path = require("path"), + cookieSession = require("cookie-session"), + cookieSessionConfig = require("./config/cookieSession.config"), + { hasData, checkPublic, checkLangQuery } = require("./utils"); // initialize application. -var app = express() +var app = express(); // view engine setup -app.set('views', path.join(__dirname, './views')) -app.set('view engine', 'pug') +app.set("views", path.join(__dirname, "./views")); +app.set("view engine", "pug"); // if NODE_ENV does not equal 'test', add a request logger -process.env.NODE_ENV !== 'test' && app.use(morgan('combined', { stream: winston.stream })) +process.env.NODE_ENV !== "test" && + app.use(morgan("combined", { stream: winston.stream })); // general app configuration. -app.use(express.json()) -app.use(express.urlencoded({ extended: false })) -app.use(cookieParser(process.env.app_session_secret)) -app.use(require('./config/i18n.config').init) +app.use(express.json()); +app.use(express.urlencoded({ extended: false })); +app.use(cookieParser(process.env.app_session_secret)); +app.use(require("./config/i18n.config").init); // in production: use redis for sessions // but this works for now -app.use(cookieSession(cookieSessionConfig)) +app.use(cookieSession(cookieSessionConfig)); // in production: precompile CSS app.use( sassMiddleware({ - src: path.join(__dirname, 'public'), - dest: path.join(__dirname, 'public'), + src: path.join(__dirname, "public"), + dest: path.join(__dirname, "public"), debug: false, indentedSyntax: false, // look for .scss files, not .sass files sourceMap: true, - outputStyle: 'compressed', - }), -) + outputStyle: "compressed" + }) +); // public assets go here (css, js, etc) -app.use(express.static(path.join(__dirname, 'public'))) +app.use(express.static(path.join(__dirname, "public"))); // dnsPrefetchControl controls browser DNS prefetching // frameguard to prevent clickjacking @@ -57,52 +58,47 @@ app.use(express.static(path.join(__dirname, 'public'))) // ieNoOpen sets X-Download-Options for IE8+ // noSniff to keep clients from sniffing the MIME type // xssFilter adds some small XSS protections -app.use(helmet()) +app.use(helmet()); // gzip response body compression. -app.use(compression()) +app.use(compression()); -app.use(checkPublic) -app.use(checkLangQuery) +app.use(checkPublic); +app.use(checkLangQuery); // Adding values/functions to app.locals means we can access them in our templates -app.locals.GITHUB_SHA = process.env.GITHUB_SHA || null -app.locals.SINFilter = SINFilter -app.locals.hasData = hasData -app.locals.currencyFilter = currencyFilter -app.locals.sortByLineNumber = sortByLineNumber +app.locals.GITHUB_SHA = process.env.GITHUB_SHA || null; +app.locals.hasData = hasData; // configure routes -require('./routes/start/start.controller')(app) -require('./routes/login/login.controller')(app) -require('./routes/personal/personal.controller')(app) -require('./routes/deductions/deductions.controller')(app) -require('./routes/dependants/dependants.controller')(app) -require('./routes/partner/partner.controller')(app) -require('./routes/financial/financial.controller')(app) -require('./routes/confirmation/confirmation.controller')(app) -require('./routes/offramp/offramp.controller')(app) +require("./routes/start/start.controller")(app); +require("./routes/login/login.controller")(app); +require("./routes/personal/personal.controller")(app); +require("./routes/confirmation/confirmation.controller")(app); +require("./routes/offramp/offramp.controller")(app); // clear session -app.get('/clear', (req, res) => { - req.session = null - res.redirect(302, '/') -}) +app.get("/clear", (req, res) => { + req.session = null; + res.redirect(302, "/"); +}); app.use(function(req, res, next) { - next(globalError(404)) -}) + next(globalError(404)); +}); // handle global errors. app.use(function(err, req, res) { - res.locals.message = err.message - res.locals.error = req.app.get('env') === 'development' ? err : {} + res.locals.message = err.message; + res.locals.error = req.app.get("env") === "development" ? err : {}; - winston.debug(`Service error: ${err}`) + winston.debug(`Service error: ${err}`); winston.error( - `${err.status || 500} - ${err.message} - ${req.originalUrl} - ${req.method} - ${req.ip}`, - ) + `${err.status || 500} - ${err.message} - ${req.originalUrl} - ${ + req.method + } - ${req.ip}` + ); - res.status(err.status || 500).json({ message: 'Internal service error.' }) -}) + res.status(err.status || 500).json({ message: "Internal service error." }); +}); -module.exports = app +module.exports = app; diff --git a/app.json b/app.json index 1f00aa9..21c980e 100755 --- a/app.json +++ b/app.json @@ -1,6 +1,6 @@ { - "name": "claim-tax-benefits", - "description": "We believe that preparing returns on behalf of people who are eligible for CVITP will result in more people receiving benefits", + "name": "notification-demo-service", + "description": "", "formation": {}, "addons": [], "buildpacks": [ diff --git a/formSchemas.js b/formSchemas.js index e13bc53..ed4f5d1 100755 --- a/formSchemas.js +++ b/formSchemas.js @@ -1,4 +1,4 @@ -const API = require('./api') +const API = require("./api"); const currencySchema = (errorMessageString = 'errors.currency') => { return { @@ -9,14 +9,14 @@ const currencySchema = (errorMessageString = 'errors.currency') => { } } -const yesNoSchema = (errorMessageString = 'errors.yesNo') => { +const yesNoSchema = (errorMessageString = "errors.yesNo") => { return { isIn: { errorMessage: errorMessageString, - options: [['Yes', 'No']], - }, - } -} + options: [["Yes", "No"]] + } + }; +}; /** * Runs an array of validators over a value @@ -24,392 +24,74 @@ const yesNoSchema = (errorMessageString = 'errors.yesNo') => { * but still maintain individual error messages */ const validationArray = validators => { - let errors = [] + let errors = []; return { custom: { errorMessage: () => { - return errors.length ? errors[0] : 'value is invalid' + return errors.length ? errors[0] : "value is invalid"; }, options: (value, { req }, opts) => { - errors = [] + errors = []; const results = validators.map(validator => { - const result = validator.validate(value, req, opts) + const result = validator.validate(value, req, opts); // If validation failed set current Error if (result === false) { - const errorMessage = validator.errorMessage || `${value} is invalid` - errors.push(errorMessage) + const errorMessage = + validator.errorMessage || `${value} is invalid`; + errors.push(errorMessage); } - return result - }) - return results.every(value => value === true) - }, - }, - } -} + return result; + }); + return results.every(value => value === true); + } + } + }; +}; const loginSchema = { code: { isLength: { - errorMessage: 'errors.login.length', - options: { min: 9, max: 9 }, + errorMessage: "errors.login.length", + options: { min: 9, max: 9 } }, isAlphanumeric: { - errorMessage: 'errors.login.alphanumeric', + errorMessage: "errors.login.alphanumeric" }, customSanitizer: { options: value => { - return value ? value.toUpperCase() : value - }, + return value ? value.toUpperCase() : value; + } }, isIn: { options: [API.getMatches()], - errorMessage: 'errors.login.code', - }, - }, -} - -const sinSchema = { - sin: { - customSanitizer: { - options: value => { - //We want to remove any spaces, dash or underscores - return value ? value.replace(/[ \-_]*/g, '') : value - }, - }, - isLength: { - errorMessage: 'errors.login.lengthSIN', - options: { min: 9, max: 9 }, - }, - isInt: { - errorMessage: 'errors.login.numericSIN', - }, - custom: { - options: (value, { req }) => { - /* If there is no session, always return true */ - if (!req.session || !req.session.personal) { - return true - } - - return value === req.session.personal.sin - }, - errorMessage: 'errors.login.sin', - }, - }, -} - -const lastDayInMonth = (year, month) => { - return new Date(year, month + 1, 0).getDate() -} - -const validBirthDateLengths = { - errorMessage: 'errors.login.dateOfBirth.format', - validate: value => { - const birthDateSplit = value.split('/') - - if (birthDateSplit.length !== 3) { - return false + errorMessage: "errors.login.code" } + } +}; - return ( - birthDateSplit[0].length === 4 && - birthDateSplit[1].length === 2 && - birthDateSplit[2].length === 2 - ) - }, -} - -const validBirthDateChars = { - errorMessage: 'errors.login.dateOfBirth.characters', - validate: value => { - const numAndSlash = new RegExp(/^[0-9/]*$/) - return numAndSlash.test(value) - }, -} - -const validMonth = { - errorMessage: 'errors.login.dateOfBirth.validMonth', - validate: value => { - //month is not less than 1 or greater than 12 - const month = parseInt(value.split('/')[1], 10) - return month >= 1 && month <= 12 - }, -} - -const validDay = { - errorMessage: 'errors.login.dateOfBirth.validDay', - validate: value => { - //day is within the acceptable range - const dateSplit = value.split('/') - //subtract one because Date for months starts at a 0 index for Jan - const month = parseInt(dateSplit[1]) - 1 - const day = parseInt(dateSplit[2], 10) - const lastDay = lastDayInMonth(dateSplit[0], month) - return day >= 1 && day <= lastDay - }, -} - -const validYear = { - errorMessage: 'errors.login.dateOfBirth.validYear', - validate: value => { - //year is within the acceptable range. Person not older than 200, not younger than 1 - //listen, if you've lived to 201, why are you even bothering with taxes? - const dateEntered = new Date(value) - const currentDate = new Date() - const year = currentDate.getFullYear() - const month = currentDate.getMonth() - const day = currentDate.getDate() - - const lastYear = new Date(year - 1, month, day) - - const longAgo = new Date(year - 200, month, day) - - return dateEntered <= lastYear && dateEntered >= longAgo - }, -} - -const isMatchingDoB = { - errorMessage: 'errors.login.dateOfBirth.match', - validate: (value, req) => { - /* If there is no session, always return true */ - if (!req.session || !req.session.personal) { - return true - } - - return value === req.session.personal.dateOfBirth - }, -} - -const birthSchema = { - dateOfBirth: { - //pro-tip: the order of the sanitizers does matter - customSanitizer: { - options: value => { - //We want to remove any spaces, dash or underscores - return value ? value.replace(/[ \-_]*/g, '') : value - }, - }, - ...validationArray([ - validBirthDateLengths, - validBirthDateChars, - validMonth, - validDay, - validYear, - isMatchingDoB, - ]), - isLength: { - errorMessage: 'errors.login.dateOfBirth', - //length with slashes - options: { min: 10, max: 10 }, - }, - }, -} - -//TODO: We'll want to store this array of marital options somewhere. This is temporary. I'll also want to use that later to create the radio buttons dynamically, to avoid having to update multiple files -const maritalStatusSchema = { - maritalStatus: { - isIn: { - errorMessage: 'errors.maritalStatus.maritalStatus', - options: [['Married', 'Widowed', 'Divorced', 'Separated', 'Single']], - }, - }, -} - -const addressSchema = { - line1: { - isEmpty: { - errorMessage: 'errors.address.line1.empty', - negated: true, - }, - }, - city: { - isEmpty: { - errorMessage: 'errors.address.city.empty', - negated: true, - }, - }, - postalCode: { - isEmpty: { - errorMessage: 'errors.address.postalCode.empty', - negated: true, - }, - custom: { - options: value => { - // Source: https://gist.github.com/nery/9118763 - var postalCodeRegex = new RegExp( - /^\s*[a-ceghj-npr-tvxy]\d[a-ceghj-npr-tv-z][-(\s)]?\d[a-ceghj-npr-tv-z]\d\s*$/i, - ) - - return postalCodeRegex.test(value) - }, - errorMessage: 'errors.address.postalCode.format', - }, - }, - province: { - isIn: { - errorMessage: 'errors.address.province', - options: [ - [ - 'Alberta', - 'British Columbia', - 'Manitoba', - 'New Brunswick', - 'Newfoundland And Labrador', - 'Northwest Territories', - 'Nova Scotia', - 'Nunavut', - 'Ontario', - 'Prince Edward Island', - 'Quebec', - 'Saskatchewan', - 'Yukon', - ], - ], - }, - }, -} - -const rrspSchema = { - rrspClaim: yesNoSchema(), -} - -const incomeSchema = { - confirmIncome: yesNoSchema(), -} - -const rrspAmountSchema = { - rrspAmount: currencySchema(), -} - -const donationsSchema = { - donationsClaim: yesNoSchema(), -} - -const donationsAmountSchema = { - donationsAmount: currencySchema(), -} - -const medicalSchema = { - medicalClaim: yesNoSchema(), -} const nameSchema = { - name: yesNoSchema(), -} - -const medicalAmountSchema = { - medicalAmount: currencySchema(), -} - -const politicalSchema = { - politicalClaim: yesNoSchema(), -} - -const politicalAmountSchema = { - politicalProvincialAmount: { - customSanitizer: { - options: value => { - return value ? value : 0 //if blank we want to assume they meant 0 - }, - }, - ...currencySchema(), - }, - politicalFederalAmount: { - customSanitizer: { - options: value => { - return value ? value : 0 //if blank we want to assume they meant 0 - }, - }, - ...currencySchema(), - }, -} - -const residenceSchema = { - residence: { - isIn: { - errorMessage: 'errors.address.province', - options: [ - [ - 'Alberta', - 'British Columbia', - 'Manitoba', - 'New Brunswick', - 'Newfoundland And Labrador', - 'Northwest Territories', - 'Nova Scotia', - 'Nunavut', - 'Ontario', - 'Prince Edward Island', - 'Quebec', - 'Saskatchewan', - 'Yukon', - 'Non Resident', - ], - ], - }, - }, -} - -const authSchema = { - auth: currencySchema(), -} - -const trilliumRentAmountSchema = { - trilliumRentAmount: currencySchema(), -} - -const trilliumPropertyTaxAmountSchema = { - trilliumPropertyTaxAmount: currencySchema(), -} - -const trilliumStudentResidenceSchema = { - trilliumStudentResidence: yesNoSchema(), -} - -const trilliumEnergyAmountSchema = { - trilliumEnergyAmount: currencySchema(), -} - -const trilliumlongTermCareAmountSchema = { - trilliumLongTermCareAmount: currencySchema(), -} + name: yesNoSchema() +}; const reviewSchema = { review: { isIn: { - errorMessage: 'errors.review', - options: [['review']], - }, - }, -} + errorMessage: "errors.review", + options: [["review"]] + } + } +}; -const climateActionIncentiveSchema = { - climateActionIncentiveIsRural: yesNoSchema(), +const authSchema = { + auth: currencySchema(), } module.exports = { loginSchema, - maritalStatusSchema, - residenceSchema, - sinSchema, - addressSchema, - birthSchema, - rrspSchema, - rrspAmountSchema, - donationsSchema, - donationsAmountSchema, - trilliumRentAmountSchema, - trilliumPropertyTaxAmountSchema, - trilliumEnergyAmountSchema, - trilliumlongTermCareAmountSchema, - trilliumStudentResidenceSchema, - climateActionIncentiveSchema, + currencySchema, reviewSchema, - politicalSchema, - politicalAmountSchema, - medicalSchema, - medicalAmountSchema, authSchema, - incomeSchema, - nameSchema, -} + nameSchema +}; diff --git a/package.json b/package.json index 4a1b13c..681dca9 100755 --- a/package.json +++ b/package.json @@ -1,8 +1,8 @@ { - "name": "claim-tax-benefits", - "version": "0.2.0", - "description": "We believe that preparing returns on behalf of people who are eligible for CVITP will result in more people receiving benefits", - "author": "pcraig3", + "name": "notification-demo-service", + "version": "0.0.1", + "description": "", + "author": "CDS", "license": "MIT", "private": true, "engines": { @@ -36,7 +36,7 @@ "devDependencies": { "cheerio": "^1.0.0-rc.3", "eslint": "^6.1.0", - "eslint-plugin-jest": "^22.14.0", + "eslint-plugin-jest": "^22.14.1", "jest": "^24.8.0", "nodemon": "^1.19.1", "supertest": "^4.0.2", diff --git a/routes/deductions/deductions.controller.js b/routes/deductions/deductions.controller.js deleted file mode 100755 index eec614f..0000000 --- a/routes/deductions/deductions.controller.js +++ /dev/null @@ -1,324 +0,0 @@ -const { checkSchema } = require('express-validator') -const { validateRedirect, checkErrors } = require('./../../utils') -const { - rrspSchema, - rrspAmountSchema, - donationsSchema, - donationsAmountSchema, - politicalSchema, - politicalAmountSchema, - medicalSchema, - medicalAmountSchema, - trilliumRentAmountSchema, - trilliumPropertyTaxAmountSchema, - trilliumStudentResidenceSchema, - trilliumEnergyAmountSchema, - trilliumlongTermCareAmountSchema, - climateActionIncentiveSchema, -} = require('./../../formSchemas.js') - -module.exports = function (app) { - //Start of RRSP Section - app.get('/deductions/rrsp', (req, res) => res.render('deductions/rrsp', { data: req.session })) - app.post( - '/deductions/rrsp', - validateRedirect, - checkSchema(rrspSchema), - checkErrors('deductions/rrsp'), - postRRSP, - ) - app.get('/deductions/rrsp/amount', (req, res) => - res.render('deductions/rrsp-amount', { data: req.session }), - ) - app.post( - '/deductions/rrsp/amount', - validateRedirect, - checkSchema(rrspAmountSchema), - checkErrors('deductions/rrsp-amount'), - postRRSPAmount, - ) - //End of RRSP Section - - //Start of Charitable Donations Section - app.get('/deductions/donations', (req, res) => - res.render('deductions/donations', { data: req.session }), - ) - app.post( - '/deductions/donations', - validateRedirect, - checkSchema(donationsSchema), - checkErrors('deductions/donations'), - postDonations, - ) - app.get('/deductions/donations/amount', (req, res) => - res.render('deductions/donations-amount', { data: req.session }), - ) - app.post( - '/deductions/donations/amount', - validateRedirect, - checkSchema(donationsAmountSchema), - checkErrors('deductions/donations-amount'), - postDonationsAmount, - ) - //End of Charitable Donations Section - - //Start of Medical claim Section - app.get('/deductions/medical', (req, res) => - res.render('deductions/medical', { data: req.session }), - ) - app.post( - '/deductions/medical', - validateRedirect, - checkSchema(medicalSchema), - checkErrors('deductions/medical'), - postMedical, - ) - app.get('/deductions/medical/amount', (req, res) => - res.render('deductions/medical-amount', { data: req.session }), - ) - app.post( - '/deductions/medical/amount', - validateRedirect, - checkSchema(medicalAmountSchema), - checkErrors('deductions/medical-amount'), - postMedicalAmount, - ) - //End of Medical Claim Section - - //Start of Political Donations Section - app.get('/deductions/political', (req, res) => res.render('deductions/political', { data: req.session })) - app.post( - '/deductions/political', - validateRedirect, - checkSchema(politicalSchema), - checkErrors('deductions/political'), - postPolitical, - ) - app.get('/deductions/political/amount', (req, res) => - res.render('deductions/political-amount', { data: req.session }), - ) - app.post( - '/deductions/political/amount', - validateRedirect, - checkSchema(politicalAmountSchema), - checkErrors('deductions/political-amount'), - postPoliticalAmount, - ) - //End of Charitable Donations Section - - //Start of Trillum Section - app.get('/trillium/rent/amount', (req, res) => - res.render('deductions/trillium-rent-amount', { data: req.session }), - ) - app.post( - '/trillium/rent/amount', - validateRedirect, - checkSchema(trilliumRentAmountSchema), - checkErrors('deductions/trillium-rent-amount'), - postTrilliumRentAmount, - ) - - - app.get('/trillium/propertyTax/amount', (req, res) => - res.render('deductions/trillium-propertyTax-amount', { data: req.session }), - ) - app.post( - '/trillium/propertyTax/amount', - validateRedirect, - checkSchema(trilliumPropertyTaxAmountSchema), - checkErrors('deductions/trillium-propertyTax-amount'), - postTrilliumPropertyTaxAmount, - ) - - app.get('/trillium/studentResidence', (req, res) => - res.render('deductions/trillium-studentResidence', { data: req.session }), - ) - app.post( - '/trillium/studentResidence', - validateRedirect, - checkSchema(trilliumStudentResidenceSchema), - checkErrors('deductions/trillium-studentResidence'), - postTrilliumStudentResidence, - ) - - app.get('/trillium/energy/amount', (req, res) => - res.render('deductions/trillium-energy-amount', { data: req.session }), - ) - app.post( - '/trillium/energy/amount', - validateRedirect, - checkSchema(trilliumEnergyAmountSchema), - checkErrors('deductions/trillium-energy-amount'), - postTrilliumEnergyAmount, - ) - - app.get('/trillium/longTermCare/amount', (req, res) => - res.render('deductions/trillium-longTermCare-amount', { data: req.session }), - ) - app.post( - '/trillium/longTermCare/amount', - validateRedirect, - checkSchema(trilliumlongTermCareAmountSchema), - checkErrors('deductions/trillium-longTermCare-amount'), - postTrilliumLongTermCareAmount, - ) - - //Climate Action Incentive - app.get('/deductions/climate-action-incentive', (req, res) => - res.render('deductions/climate-action-incentive', { data: req.session }), - ) - app.post( - '/deductions/climate-action-incentive', - validateRedirect, - checkSchema(climateActionIncentiveSchema), - checkErrors('deductions/climate-action-incentive'), - postClimateActionIncentiveSchema, - ) -} - -//Start of RRSP controller functions -const postRRSP = (req, res) => { - const rrspClaim = req.body.rrspClaim - - if (rrspClaim === 'Yes') { - req.session.deductions.rrspClaim = true - - // It's fine not having this in the form itself (like the other redirect value) - // because these two pages are hardcoded together - return res.redirect('/deductions/rrsp/amount') - } - - req.session.deductions.rrspClaim = false - - //Success, we can redirect to the next page - return res.redirect(req.body.redirect) -} - -const postRRSPAmount = (req, res) => { - req.session.deductions.rrspAmount.amount = req.body.rrspAmount - - //Success, we can redirect to the next page - return res.redirect(req.body.redirect) -} -// End of RRSP controller functions - -//Start of Charitable Donations controller functions -const postDonations = (req, res) => { - const donationsClaim = req.body.donationsClaim - - if (donationsClaim === 'Yes') { - req.session.deductions.charitableDonationClaim = true - - // It's fine not having this in the form itself (like the other redirect value) - // because these two pages are hardcoded together - return res.redirect('/deductions/donations/amount') - } - - req.session.deductions.charitableDonationClaim = false - - //Success, we can redirect to the next page - return res.redirect(req.body.redirect) -} - -const postDonationsAmount = (req, res) => { - req.session.deductions.charitableDonationAmount = req.body.donationsAmount - - //Success, we can redirect to the next page - return res.redirect(req.body.redirect) -} -//End of Charitable Donations controller functions - -//Start of Medical claim controller functions -const postMedical = (req, res) => { - const medicalClaim = req.body.medicalClaim - - if (medicalClaim === 'Yes') { - req.session.deductions.medicalExpenseClaim = true - - // It's fine not having this in the form itself (like the other redirect value) - // because these two pages are hardcoded together - return res.redirect('/deductions/medical/amount') - } - - req.session.deductions.medicalExpenseClaim = false - - //Success, we can redirect to the next page - return res.redirect(req.body.redirect) -} - -const postMedicalAmount = (req, res) => { - req.session.deductions.medicalExpenseClaimAmount.amount = req.body.medicalAmount - - //Success, we can redirect to the next page - return res.redirect(req.body.redirect) -} -//End of Medical claim controller functions - - -//Start of Trillium controller functions -const postTrilliumRentAmount = (req, res) => { - req.session.deductions.trilliumRentAmount = req.body.trilliumRentAmount - - //Success, we can redirect to the next page - return res.redirect(req.body.redirect) -} - -const postTrilliumPropertyTaxAmount = (req, res) => { - req.session.deductions.trilliumPropertyTaxAmount = req.body.trilliumPropertyTaxAmount - - //Success, we can redirect to the next page - return res.redirect(req.body.redirect) -} - -const postTrilliumStudentResidence = (req, res) => { - req.session.deductions.trilliumStudentResidence = - req.body.trilliumStudentResidence === 'Yes' ? true : false - - return res.redirect(req.body.redirect) -} - -const postTrilliumEnergyAmount = (req, res) => { - req.session.deductions.trilliumEnergyAmount = req.body.trilliumEnergyAmount - - //Success, we can redirect to the next page - return res.redirect(req.body.redirect) -} - -const postTrilliumLongTermCareAmount = (req, res) => { - req.session.deductions.trilliumLongTermCareAmount = req.body.trilliumLongTermCareAmount - //Success, we can redirect to the next page - return res.redirect(req.body.redirect) -} - -//Start of Political Political controller functions -const postPolitical = (req, res) => { - const politicalClaim = req.body.politicalClaim - - if (politicalClaim === 'Yes') { - req.session.deductions.politicalClaim = true - - // It's fine not having this in the form itself (like the other redirect value) - // because these two pages are hardcoded together - return res.redirect('/deductions/political/amount') - } - - req.session.deductions.politicalClaim = false - - //Success, we can redirect to the next page - return res.redirect(req.body.redirect) -} - -const postPoliticalAmount = (req, res) => { - req.session.deductions.politicalFederalAmount = req.body.politicalFederalAmount - req.session.deductions.politicalProvincialAmount = req.body.politicalProvincialAmount - //Success, we can redirect to the next page - return res.redirect(req.body.redirect) -} - -const postClimateActionIncentiveSchema = (req, res) => { - req.session.deductions.climateActionIncentiveIsRural = req.body.climateActionIncentiveIsRural - //Success, we can redirect to the next page - return res.redirect(req.body.redirect) -} - - diff --git a/routes/deductions/deductions.spec.js b/routes/deductions/deductions.spec.js deleted file mode 100755 index e5acbe7..0000000 --- a/routes/deductions/deductions.spec.js +++ /dev/null @@ -1,302 +0,0 @@ -const request = require('supertest') -const app = require('../../app.js') - -describe('Test /deductions responses', () => { - //Start of RRSP section - describe('Test /deductions/rrsp responses', () => { - test('it redirects to the edit page when posting "Yes"', async () => { - const response = await request(app) - .post('/deductions/rrsp') - .send({ rrspClaim: 'Yes', redirect: '/' }) - expect(response.statusCode).toBe(302) - expect(response.headers.location).toEqual('/deductions/rrsp/amount') - }) - - test('it redirects to the posted redirect url when posting "No"', async () => { - const response = await request(app) - .post('/deductions/rrsp') - .send({ rrspClaim: 'No', redirect: '/' }) - expect(response.statusCode).toBe(302) - expect(response.headers.location).toEqual('/') - }) - }) - - //Start of Medical Claim section - describe('Test /deductions/medical responses', () => { - test('it redirects to the edit page when posting "Yes"', async () => { - const response = await request(app) - .post('/deductions/medical') - .send({ medicalClaim: 'Yes', redirect: '/' }) - expect(response.statusCode).toBe(302) - expect(response.headers.location).toEqual('/deductions/medical/amount') - }) - - test('it redirects to the posted redirect url when posting "No"', async () => { - const response = await request(app) - .post('/deductions/medical') - .send({ medicalClaim: 'No', redirect: '/' }) - expect(response.statusCode).toBe(302) - expect(response.headers.location).toEqual('/') - }) - }) - //End of Medical Claim section - - //Start of Charitable donation section - describe('Test /deductions/donations responses', () => { - test('it redirects to the edit page when posting "Yes"', async () => { - const response = await request(app) - .post('/deductions/donations') - .send({ donationsClaim: 'Yes', redirect: '/' }) - expect(response.statusCode).toBe(302) - expect(response.headers.location).toEqual('/deductions/donations/amount') - }) - - test('it redirects to the posted redirect url when posting "No"', async () => { - const response = await request(app) - .post('/deductions/donations') - .send({ donationsClaim: 'No', redirect: '/' }) - expect(response.statusCode).toBe(302) - expect(response.headers.location).toEqual('/') - }) - }) - - //Start of political donations - describe('Test /deductions/political responses', () => { - test('it returns a 200 response for /deductions/political', async () => { - const response = await request(app).get('/deductions/political') - expect(response.statusCode).toBe(200) - }) - - test('it returns a 422 response for no posted value', async () => { - const response = await request(app) - .post('/deductions/political') - .send({ redirect: '/' }) - expect(response.statusCode).toBe(422) - }) - - //Bad Federal amounts, good provincial amounts - const badFederalPoliticalAmounts = ['dinosaur', '10.0', '10.000', '-10', '.1'] - badFederalPoliticalAmounts.map(politicalFederalAmount => { - test(`it returns a 422 for a bad federal and good provincial posted value: "${politicalFederalAmount}"`, async () => { - const politicalProvincialAmount = 10 - const response = await request(app) - .post('/deductions/political/amount') - .send({ - politicalFederalAmount, - politicalProvincialAmount, - redirect: '/', - }) - expect(response.statusCode).toBe(422) - }) - }) - - //Bad provincial amounts, good federal amounts - const badPoliticalProvincialAmount = ['dinosaur', '10.0', '10.000', '-10', '.1'] - badPoliticalProvincialAmount.map(politicalProvincialAmount => { - test(`it returns a 422 for a bad provincial and good federal posted value: "${politicalProvincialAmount}"`, async () => { - const politicalFederalAmount = 10 - const response = await request(app) - .post('/deductions/political/amount') - .send({ - politicalFederalAmount, - politicalProvincialAmount, - redirect: '/', - }) - expect(response.statusCode).toBe(422) - }) - }) - - //Bad provincial amounts, bad federal amounts - const badPoliticalAmount = ['dinosaur', '10.0', '10.000', '-10', '.1'] - badPoliticalAmount.map(politicalAmount => { - test(`it returns a 422 for a bad provincial and bad federal posted value: "${politicalAmount}"`, async () => { - const response = await request(app) - .post('/deductions/political/amount') - .send({ - politicalFederalAmount: politicalAmount, - politicalProvincialAmount: politicalAmount, - redirect: '/', - }) - expect(response.statusCode).toBe(422) - }) - }) - - //Good provincial amounts, good federal amounts - const goodPoliticalAmounts = ['', null, '0', '10', '10.00', '.10'] //For this page empty is a valid value to pass - goodPoliticalAmounts.map(politicalAmount => { - test(`it returns a 302 for both good posted value: "${politicalAmount}"`, async () => { - const response = await request(app) - .post('/deductions/political/amount') - .send({ - politicalFederalAmount: politicalAmount, - politicalProvincialAmount: politicalAmount, - redirect: '/', - }) - expect(response.statusCode).toBe(302) - }) - }) - }) - // Start of the trillium student residence section - describe('Test /trillium/studentResidence responses', () => { - test('it redirects to the posted redirect url when posting "Yes"', async () => { - const response = await request(app) - .post('/trillium/studentResidence') - .send({ trilliumStudentResidence: 'Yes', redirect: '/' }) - expect(response.statusCode).toBe(302) - expect(response.headers.location).toEqual('/') - }) - - test('it redirects to the posted redirect url when posting "No"', async () => { - const response = await request(app) - .post('/trillium/studentResidence') - .send({ trilliumStudentResidence: 'No', redirect: '/' }) - expect(response.statusCode).toBe(302) - expect(response.headers.location).toEqual('/') - }) - }) - - // Start of the Climate Action Incentive section - describe('Test /deductions/climate-action-incentive responses', () => { - test('it redirects to the posted redirect url when posting "Yes"', async () => { - const response = await request(app) - .post('/deductions/climate-action-incentive') - .send({ climateActionIncentiveIsRural: 'Yes', redirect: '/' }) - expect(response.statusCode).toBe(302) - expect(response.headers.location).toEqual('/') - }) - - test('it redirects to the posted redirect url when posting "No"', async () => { - const response = await request(app) - .post('/deductions/climate-action-incentive') - .send({ climateActionIncentiveIsRural: 'No', redirect: '/' }) - expect(response.statusCode).toBe(302) - expect(response.headers.location).toEqual('/') - }) - }) - - describe('Test /deductions/* yesNo responses', () => { - const yesNoResponses = [ - { - url: '/deductions/rrsp', - key: 'rrspClaim', - }, - { - url: '/deductions/medical', - key: 'medicalClaim', - }, - { - url: '/deductions/donations', - key: 'donationsClaim', - }, - { - url: '/trillium/studentResidence', - key: 'trilliumStudentResidence', - }, - { - url: '/deductions/political', - key: 'politicalClaim', - }, - ] - - yesNoResponses.map(yesNoResponse => { - describe(`Test ${yesNoResponse.url} responses`, () => { - test('it returns a 200 response', async () => { - const response = await request(app).get(yesNoResponse.url) - expect(response.statusCode).toBe(200) - }) - - test('it returns a 422 response for no posted value', async () => { - const response = await request(app) - .post(yesNoResponse.url) - .send({ redirect: '/' }) - expect(response.statusCode).toBe(422) - }) - - const badValues = ['', null, false, 0, 'dinosaur', 'yes'] - badValues.map(badValue => { - test(`it returns a 422 for a bad posted value: "${badValue}"`, async () => { - const response = await request(app) - .post(yesNoResponse.url) - .send({ [yesNoResponse.key]: badValue, redirect: '/' }) - expect(response.statusCode).toBe(422) - }) - }) - }) - }) - }) - - describe('Test /deductions/*/amount responses', () => { - const amountReponses = [ - { - url: '/deductions/rrsp/amount', - key: 'rrspAmount', - }, - { - url: '/deductions/medical/amount', - key: 'medicalAmount', - }, - { - url: '/deductions/donations/amount', - key: 'donationsAmount', - }, - { - url: '/trillium/rent/amount', - key: 'trilliumRentAmount', - }, - { - url: '/trillium/propertyTax/amount', - key: 'trilliumPropertyTaxAmount', - }, - { - url: '/trillium/energy/amount', - key: 'trilliumEnergyAmount', - }, - { - url: '/trillium/longTermCare/amount', - key: 'trilliumLongTermCareAmount', - }, - ] - - amountReponses.map(amountResponse => { - describe(`Test ${amountResponse.url} responses`, () => { - test('it returns a 200 response', async () => { - const response = await request(app).get(amountResponse.url) - expect(response.statusCode).toBe(200) - }) - - test('it returns a 500 response if no redirect is provided', async () => { - const response = await request(app).post(amountResponse.url) - expect(response.statusCode).toBe(500) - }) - - test('it returns a 422 response for no posted value', async () => { - const response = await request(app) - .post(amountResponse.url) - .send({ redirect: '/' }) - expect(response.statusCode).toBe(422) - }) - - const badAmounts = ['', null, 'dinosaur', '10.0', '10.000', '-10', '.1'] - badAmounts.map(badAmount => { - test(`it returns a 422 for a bad posted value: "${badAmount}"`, async () => { - const response = await request(app) - .post(amountResponse.url) - .send({ [amountResponse.key]: badAmount, redirect: '/' }) - expect(response.statusCode).toBe(422) - }) - }) - - const goodAmounts = ['0', '10', '10.00', '.10'] - goodAmounts.map(goodAmount => { - test(`it returns a 302 for a good posted value: "${goodAmount}"`, async () => { - const response = await request(app) - .post(amountResponse.url) - .send({ [amountResponse.key]: goodAmount, redirect: '/' }) - expect(response.statusCode).toBe(302) - expect(response.headers.location).toEqual('/') - }) - }) - }) - }) - }) -}) diff --git a/routes/dependants/dependants.controller.js b/routes/dependants/dependants.controller.js deleted file mode 100755 index 703f826..0000000 --- a/routes/dependants/dependants.controller.js +++ /dev/null @@ -1,26 +0,0 @@ -const { validationResult } = require('express-validator') -const { errorArray2ErrorObject, validateRedirect } = require('./../../utils') - -module.exports = function(app) { - // redirect from "/dependants" → "/login/code", you really shouldn't be here (Unless we add a "info" page) - app.get('/dependants', (req, res) => res.redirect('/login/code')) - - app.get('/dependants/children', (req, res) => - res.render('dependants/children', { data: req.session || {} }), - ) - app.post('/dependants/children', validateRedirect, postChildren) -} - -const postChildren = (req, res) => { - const errors = validationResult(req) - - if (!errors.isEmpty()) { - return res.status(422).render('dependants/children', { - data: { children: req.body.children } || {}, - errors: errorArray2ErrorObject(errors), - }) - } - - //Success, we can redirect to the next page - return res.redirect(req.body.redirect) -} diff --git a/routes/dependants/dependants.spec.js b/routes/dependants/dependants.spec.js deleted file mode 100755 index 7c1cbbf..0000000 --- a/routes/dependants/dependants.spec.js +++ /dev/null @@ -1,25 +0,0 @@ -const request = require('supertest') -const app = require('../../app.js') - - - -describe('Test /dependants responses', () => { - - test('it redirects to /login/code from /dependants', async () => { - const response = await request(app).get('/dependants') - expect(response.statusCode).toBe(302) - expect(response.headers.location).toEqual('/login/code') - }) - - - test('it returns a 200 response for /dependants/children', async () => { - const response = await request(app).get('/dependants/children') - expect(response.statusCode).toBe(200) - }) - - test('it returns a 500 response if no redirect is provided', async () => { - const response = await request(app).post('/dependants/children') - expect(response.statusCode).toBe(500) - }) - -}) \ No newline at end of file diff --git a/routes/financial/financial.controller.js b/routes/financial/financial.controller.js deleted file mode 100755 index 75ae2a5..0000000 --- a/routes/financial/financial.controller.js +++ /dev/null @@ -1,31 +0,0 @@ -const { checkSchema } = require('express-validator') -const { validateRedirect, checkErrors } = require('./../../utils') -const { incomeSchema } = require('./../../formSchemas.js') - -module.exports = function(app) { - app.get('/financial/income', (req, res) => - //TODO: update this with proper date later - res.render('financial/income', { data: req.session }), - ) - - app.post( - '/financial/income', - validateRedirect, - checkSchema(incomeSchema), - checkErrors('financial/income'), - postConfirmIncome, - ) -} - -const postConfirmIncome = (req, res) => { - const confirmIncome = req.body.confirmIncome - - if (confirmIncome === 'No') { - //Income details are not correct - //Lead them to the offramp - return res.redirect('/offramp/financial') - } - - //Income confirmed, can continue normally - return res.redirect(req.body.redirect) -} \ No newline at end of file diff --git a/routes/financial/financial.spec.js b/routes/financial/financial.spec.js deleted file mode 100755 index 40170f1..0000000 --- a/routes/financial/financial.spec.js +++ /dev/null @@ -1,32 +0,0 @@ -const request = require('supertest') -const app = require('../../app.js') - -describe('Test /financial responses', () => { - test('it returns a 200 response for /financial/income', async () => { - const response = await request(app).get('/financial/income') - expect(response.statusCode).toBe(200) - }) - - test('it returns a 422 with no option selected', async () => { - const response = await request(app) - .post('/financial/income') - .send({ redirect: '/deductions/rrsp' }) - expect(response.statusCode).toBe(422) - }) - - test('it returns a 302 and redirects to offramp when NO is selected', async () => { - const response = await request(app) - .post('/financial/income') - .send({ confirmIncome: 'No', redirect: '/offramp/financial' }) - expect(response.statusCode).toBe(302) - expect(response.headers.location).toEqual('/offramp/financial') - }) - - test('it returns a 302 and redirects to the same page when YES is selected', async () => { - const response = await request(app) - .post('/financial/income') - .send({ confirmIncome: 'Yes', redirect: '/deductions/rrsp' }) - expect(response.statusCode).toBe(302) - expect(response.headers.location).toEqual('/deductions/rrsp') - }) -}) \ No newline at end of file diff --git a/routes/login/login.controller.js b/routes/login/login.controller.js index 6014840..f350ebf 100755 --- a/routes/login/login.controller.js +++ b/routes/login/login.controller.js @@ -1,6 +1,6 @@ const { validationResult, checkSchema } = require('express-validator') const { errorArray2ErrorObject, validateRedirect, checkErrors } = require('./../../utils') -const { loginSchema, sinSchema, birthSchema, authSchema } = require('./../../formSchemas.js') +const { loginSchema, birthSchema, authSchema } = require('./../../formSchemas.js') const API = require('../../api') module.exports = function(app) { @@ -9,28 +9,6 @@ module.exports = function(app) { app.get('/login/code', (req, res) => res.render('login/code', { data: req.session || {} })) app.post('/login/code', validateRedirect, checkSchema(loginSchema), postLoginCode) - // SIN - app.get('/login/sin', (req, res) => res.render('login/sin', { data: req.session })) - app.post( - '/login/sin', - validateRedirect, - checkSchema(sinSchema), - checkErrors('login/sin'), - postSIN, - ) - - // Date of Birth - app.get('/login/dateOfBirth', (req, res) => - res.render('login/dateOfBirth', { data: req.session }), - ) - app.post( - '/login/dateOfBirth', - validateRedirect, - checkSchema(birthSchema), - checkErrors('login/dateOfBirth'), - postDoB, - ) - // Auth page app.get('/login/auth', getAuth) app.post('/login/auth', checkSchema(authSchema), checkErrors('login/auth'), postAuth) @@ -59,16 +37,6 @@ const postLoginCode = (req, res) => { return res.redirect(req.body.redirect) } -const postSIN = (req, res) => { - //Success, we can redirect to the next page - return res.redirect(req.body.redirect) -} - -const postDoB = (req, res) => { - //Success, we can redirect to the next page - return res.redirect(req.body.redirect) -} - const getAuth = (req, res) => { if (!req.query.redirect) { return res.redirect('/start') diff --git a/routes/login/login.spec.js b/routes/login/login.spec.js index 8522dea..505dfcc 100755 --- a/routes/login/login.spec.js +++ b/routes/login/login.spec.js @@ -1,327 +1,119 @@ -const request = require('supertest') -const session = require('supertest-session') -const cheerio = require('cheerio') -const app = require('../../app.js') +const request = require("supertest"); +const session = require("supertest-session"); +const cheerio = require("cheerio"); +const app = require("../../app.js"); -describe('Test /login responses', () => { +describe("Test /login responses", () => { //login page - test('it redirects to /login/code from /login', async () => { - const response = await request(app).get('/login') - expect(response.statusCode).toBe(302) - expect(response.headers.location).toEqual('/login/code') - }) + test("it redirects to /login/code from /login", async () => { + const response = await request(app).get("/login"); + expect(response.statusCode).toBe(302); + expect(response.headers.location).toEqual("/login/code"); + }); //login/code - test('it returns a 200 response for /login/code', async () => { - const response = await request(app).get('/login/code') - expect(response.statusCode).toBe(200) - }) - - test('it renders the h1 text for /login/code', async () => { - const response = await request(app).get('/login/code') - - const $ = cheerio.load(response.text) - expect($('h1').text()).toEqual('Enter your personal access code') - }) - - test('it returns a 500 response if no redirect is provided', async () => { - const response = await request(app).post('/login/code') - expect(response.statusCode).toBe(500) - }) - - test('it autofocuses on the single input on the page', async () => { - const response = await request(app).get('/login/code') - const $ = cheerio.load(response.text) - expect($('#code').attr('autofocus')).toEqual('autofocus') - }) - - test('it reloads /login/code with a 422 status if no code is provided', async () => { + test("it returns a 200 response for /login/code", async () => { + const response = await request(app).get("/login/code"); + expect(response.statusCode).toBe(200); + }); + + test("it renders the h1 text for /login/code", async () => { + const response = await request(app).get("/login/code"); + + const $ = cheerio.load(response.text); + expect($("h1").text()).toEqual("Enter your personal access code"); + }); + + test("it returns a 500 response if no redirect is provided", async () => { + const response = await request(app).post("/login/code"); + expect(response.statusCode).toBe(500); + }); + + test("it autofocuses on the single input on the page", async () => { + const response = await request(app).get("/login/code"); + const $ = cheerio.load(response.text); + expect($("#code").attr("autofocus")).toEqual("autofocus"); + }); + + test("it reloads /login/code with a 422 status if no code is provided", async () => { const response = await request(app) - .post('/login/code') - .send({ redirect: '/' }) - expect(response.statusCode).toBe(422) - }) + .post("/login/code") + .send({ redirect: "/" }); + expect(response.statusCode).toBe(422); + }); - describe('Error list tests', () => { - test('it renders the error-list for /login/code', async () => { + describe("Error list tests", () => { + test("it renders the error-list for /login/code", async () => { const response = await request(app) - .post('/login/code') - .send({ redirect: '/' }) - const $ = cheerio.load(response.text) - expect($('title').text()).toMatch(/^Error:/) - expect($('.error-list__header').text()).toEqual('Please correct the errors on the page') - expect($('.error-list__list').children()).toHaveLength(1) - expect($('.validation-message').text()).toEqual('Error: Access code must be 9 characters') - expect($('#code').attr('aria-describedby')).toEqual('code-error') - expect($('#code').attr('autofocus')).toEqual('autofocus') - }) - - test('it renders an inline error for /login/code with appropriate describedby', async () => { + .post("/login/code") + .send({ redirect: "/" }); + const $ = cheerio.load(response.text); + expect($("title").text()).toMatch(/^Error:/); + expect($(".error-list__header").text()).toEqual( + "Please correct the errors on the page" + ); + expect($(".error-list__list").children()).toHaveLength(1); + expect($(".validation-message").text()).toEqual( + "Error: Access code must be 9 characters" + ); + expect($("#code").attr("aria-describedby")).toEqual("code-error"); + expect($("#code").attr("autofocus")).toEqual("autofocus"); + }); + + test("it renders an inline error for /login/code with appropriate describedby", async () => { const response = await request(app) - .post('/login/code') - .send({ redirect: '/' }) - const $ = cheerio.load(response.text) - expect($('.validation-message').text()).toEqual('Error: Access code must be 9 characters') - expect($('#code').attr('aria-describedby')).toEqual('code-error') - }) - }) - - test('it does not allow a code more than 9 characters', async () => { + .post("/login/code") + .send({ redirect: "/" }); + const $ = cheerio.load(response.text); + expect($(".validation-message").text()).toEqual( + "Error: Access code must be 9 characters" + ); + expect($("#code").attr("aria-describedby")).toEqual("code-error"); + }); + }); + + test("it does not allow a code more than 9 characters", async () => { const response = await request(app) - .post('/login/code') - .send({ code: '23XGY12111', redirect: '/' }) - expect(response.statusCode).toBe(422) - }) + .post("/login/code") + .send({ code: "23XGY12111", redirect: "/" }); + expect(response.statusCode).toBe(422); + }); - test('it does not allow a code less than 8 characters', async () => { + test("it does not allow a code less than 8 characters", async () => { const response = await request(app) - .post('/login/code') - .send({ code: 'A23X', redirect: '/' }) - expect(response.statusCode).toBe(422) - }) + .post("/login/code") + .send({ code: "A23X", redirect: "/" }); + expect(response.statusCode).toBe(422); + }); - test('it does not allow non-alphanumeric characters', async () => { + test("it does not allow non-alphanumeric characters", async () => { const response = await request(app) - .post('/login/code') - .send({ code: 'A23X456@', redirect: '/' }) - expect(response.statusCode).toBe(422) - }) + .post("/login/code") + .send({ code: "A23X456@", redirect: "/" }); + expect(response.statusCode).toBe(422); + }); - const codes = ['A5G98S4K1', 'a5g98S4K1', 'a5g98s4k1'] //check uppercase, lowercase and mixedcase + const codes = ["A5G98S4K1", "a5g98S4K1", "a5g98s4k1"]; //check uppercase, lowercase and mixedcase codes.map(code => { test(`it redirects if a valid code is provided: "${code}"`, async () => { const response = await request(app) - .post('/login/code') - .send({ code, redirect: '/' }) - expect(response.statusCode).toBe(302) - expect(response.headers.location).toEqual('/') - }) - }) - - test('it does not allow non-numeric characters', async () => { + .post("/login/code") + .send({ code, redirect: "/" }); + expect(response.statusCode).toBe(302); + expect(response.headers.location).toEqual("/"); + }); + }); + + test("it does not allow non-numeric characters", async () => { const response = await request(app) - .post('/login/code') - .send({ code: 'A23X456@1', redirect: '/' }) - expect(response.statusCode).toBe(422) - }) - - describe('Test /login/sin responses', () => { - // Social Insurance Number Page /login/sin - test('it returns a 200 response for /login/sin', async () => { - const response = await request(app).get('/login/sin') - expect(response.statusCode).toBe(200) - }) - - test('it renders the h1 text for /login/sin', async () => { - const response = await request(app).get('/login/sin') - - const $ = cheerio.load(response.text) - expect($('h1').text()).toEqual('Enter your Social Insurance Number (SIN)') - }) - - test('it returns a 500 response if no redirect is provided', async () => { - const response = await request(app).post('/login/sin') - expect(response.statusCode).toBe(500) - }) - - test('it reloads /login/sin with a 422 status if no sin is provided', async () => { - const response = await request(app) - .post('/login/sin') - .send({ redirect: '/' }) - expect(response.statusCode).toBe(422) - const $ = cheerio.load(response.text) - expect($('title').text()).toMatch(/^Error:/) - expect($('.error-list__header').text()).toEqual('Please correct the errors on the page') - expect($('.error-list__list').children()).toHaveLength(1) - expect($('.validation-message').text()).toEqual('Error: Your SIN should have 9 numbers') - expect($('#sin').attr('aria-describedby')).toEqual('sin-error') - }) - - describe('Error list tests', () => { - test('it renders the error-list for /login/sin', async () => { - const response = await request(app) - .post('/login/sin') - .send({ redirect: '/' }) - const $ = cheerio.load(response.text) - expect($('title').text()).toMatch(/^Error:/) - expect($('.error-list__header').text()).toEqual('Please correct the errors on the page') - expect($('.error-list__list').children()).toHaveLength(1) - expect($('.validation-message').text()).toEqual('Error: Your SIN should have 9 numbers') - expect($('#sin').attr('aria-describedby')).toEqual('sin-error') - }) - }) - - test('it does not allow a code more than 9 characters', async () => { - const response = await request(app) - .post('/login/sin') - .send({ code: '12345678910', redirect: '/' }) - expect(response.statusCode).toBe(422) - }) - - test('it does not allow a code less than 9 characters', async () => { - const response = await request(app) - .post('/login/sin') - .send({ code: '12345678', redirect: '/' }) - expect(response.statusCode).toBe(422) - }) - - /* - These tests make sure that a SIN which would ordinarily be - accepted (ie, "123456789") is no longer accepted after - a user logs in. - - After that, only the sin used by the user in /api/user.json - will be accepted. - */ - describe('after entering an access code', () => { - let authSession - - beforeEach(async () => { - authSession = session(app) - const response = await authSession - .post('/login/code') - .send({ code: 'A5G98S4K1', redirect: '/login/sin' }) - expect(response.statusCode).toBe(302) - }) - - it('it should return 422 for the wrong SIN', async () => { - const response = await authSession - .post('/login/sin') - .send({ sin: '123456789', redirect: '/login/sin' }) - expect(response.statusCode).toBe(422) - }) - - it('it should return 302 for the right SIN', async () => { - const response = await authSession - .post('/login/sin') - .send({ sin: '847 339 283', redirect: '/login/sin' }) - expect(response.statusCode).toBe(302) - }) - }) - }) + .post("/login/code") + .send({ code: "A23X456@1", redirect: "/" }); + expect(response.statusCode).toBe(422); + }); //it returns a 200 response for /login/dateOfBirth //access code test (look above for sin) - describe('Test login/dateOfBirth responses', () => { - test('it returns a 200 response for /login/dateOfBirth', async () => { - const response = await request(app).get('/login/dateOfBirth') - expect(response.statusCode).toBe(200) - }) - - let goodDoBRequest = { - dateOfBirth: '1977/09/09', - sin: '847339283', - redirect: '/login/success', - } - - const currentDate = new Date() - const year = currentDate.getFullYear() - const month = currentDate.getMonth() - const day = currentDate.getDate() - - const dateToString = dateInput => { - const add0 = s => { - return s < 10 ? '0' + s : s - } - const d = new Date(dateInput) - return [d.getFullYear(), add0(d.getMonth() + 1), add0(d.getDate())].join('/') - } - - const fewMonthsAgo = dateToString(new Date(year, month - 3, day)) - - const tooLongAgo = dateToString(new Date(year - 201, month, day)) - - const badDoBRequests = [ - { - label: 'no date of birth', - send: { - ...goodDoBRequest, - ...{ dateOfBirth: '' }, - }, - }, - { - label: 'date of birth over 10 characters', - send: { - ...goodDoBRequest, - ...{ dateOfBirth: '1977/09/222' }, - }, - }, - { - label: 'date of birth less than 10 characters', - send: { - ...goodDoBRequest, - ...{ dateOfBirth: '1909/03/2' }, - }, - }, - { - label: 'date of birth includes not allowed characters', - send: { - ...goodDoBRequest, - ...{ dateOfBirth: '1909/03/ee' }, - }, - }, - { - label: 'date of birth month is less than 1', - send: { - ...goodDoBRequest, - ...{ dateOfBirth: '1909/00/22' }, - }, - }, - { - label: 'date of birth month is greater than 12', - send: { - ...goodDoBRequest, - ...{ dateOfBirth: '1909/13/22' }, - }, - }, - { - label: 'date of birth day is less than 1', - send: { - ...goodDoBRequest, - ...{ dateOfBirth: '1909/01/00' }, - }, - }, - { - label: 'date of birth day is greater than in that month', - send: { - ...goodDoBRequest, - ...{ dateOfBirth: '2017/02/29' }, - }, - }, - { - label: 'date of birth is less than a year ago', - send: { - ...goodDoBRequest, - ...{ dateOfBirth: fewMonthsAgo }, - }, - }, - { - label: 'date of birth is more than 200 years ago', - send: { - ...goodDoBRequest, - ...{ dateOfBirth: tooLongAgo }, - }, - }, - ] - - badDoBRequests.map(badRequest => { - test(`it returns a 422 with: "${badRequest.label}"`, async () => { - const response = await request(app) - .post('/login/dateOfBirth') - .send(badRequest.send) - expect(response.statusCode).toBe(422) - }) - }) - - test('it returns a 302 with valid dob', async () => { - const response = await request(app) - .post('/login/dateOfBirth') - .send(goodDoBRequest) - expect(response.statusCode).toBe(302) - }) - }) - /* These tests make sure that a date of birth which would ordinarily be is no longer accepted after a user logs in. @@ -329,94 +121,84 @@ describe('Test /login responses', () => { After that, only the date of birth corressponding to the user in /api/user.json will be accepted. */ - describe('after entering an access code', () => { - let authSession + describe("after entering an access code", () => { + let authSession; beforeEach(async () => { - authSession = session(app) + authSession = session(app); const response = await authSession - .post('/login/code') - .send({ code: 'A5G98S4K1', redirect: '/login/sin' }) + .post("/login/code") + .send({ code: "A5G98S4K1", redirect: "/login/sin" }) .then(() => { return authSession - .post('/login/sin') - .send({ code: 'A5G98S4K1', sin: '847339283', redirect: '/login/dateOfBirth' }) - }) - expect(response.statusCode).toBe(302) - }) - - it('it should return 422 for the wrong DoB', async () => { - const response = await authSession - .post('/login/dateOfBirth') - .send({ dateOfBirth: '1909/03/23', redirect: '/login/success' }) - expect(response.statusCode).toBe(422) - }) - - it('it should return 302 for the right DoB', async () => { - const response = await authSession - .post('/login/dateOfBirth') - .send({ dateOfBirth: '1977/09/09', redirect: '/login/success' }) - expect(response.statusCode).toBe(302) - }) - }) - - describe('Test /login/auth responses', () => { + .post("/login/sin") + .send({ + code: "A5G98S4K1", + sin: "847339283", + redirect: "/login/dateOfBirth" + }); + }); + expect(response.statusCode).toBe(302); + }); + }); + + describe("Test /login/auth responses", () => { test('it returns a 302 response to the start page when no "redirect" query parameter', async () => { - const response = await request(app).get('/login/auth') - expect(response.statusCode).toBe(302) - expect(response.headers.location).toEqual('/start') - }) + const response = await request(app).get("/login/auth"); + expect(response.statusCode).toBe(302); + expect(response.headers.location).toEqual("/start"); + }); test('it returns a 200 response when containing a "redirect" query parameter', async () => { - const response = await request(app).get('/login/auth?redirect=%2Furl') - expect(response.statusCode).toBe(200) - }) + const response = await request(app).get("/login/auth?redirect=%2Furl"); + expect(response.statusCode).toBe(200); + }); - test('it returns a 422 response for no posted value', async () => { - const response = await request(app).post('/login/auth') - expect(response.statusCode).toBe(422) - }) + test("it returns a 422 response for no posted value", async () => { + const response = await request(app).post("/login/auth"); + expect(response.statusCode).toBe(422); + }); - const badAuths = ['', null, 'dinosaur', '10.0', '10.000', '-10', '.1'] + const badAuths = ["", null, "dinosaur", "10.0", "10.000", "-10", ".1"]; badAuths.map(auth => { test(`it returns a 422 for a bad posted value: "${auth}"`, async () => { const response = await request(app) - .post('/login/auth') - .send({ auth }) - expect(response.statusCode).toBe(422) - }) - }) + .post("/login/auth") + .send({ auth }); + expect(response.statusCode).toBe(422); + }); + }); - const goodAuths = ['0', '10', '10.00', '.10'] + const goodAuths = ["0", "10", "10.00", ".10"]; goodAuths.map(auth => { test(`it returns a 302 for a good posted value: "${auth}"`, async () => { const response = await request(app) - .post('/login/auth?redirect=%2Furl') - .send({ auth }) - expect(response.statusCode).toBe(302) - expect(response.headers.location).toEqual('/url') - }) - }) + .post("/login/auth?redirect=%2Furl") + .send({ auth }); + expect(response.statusCode).toBe(302); + expect(response.headers.location).toEqual("/url"); + }); + }); test('it returns a 302 response to the start page when posting a good value but no "redirect" query parameter', async () => { const response = await request(app) - .post('/login/auth') - .send({ auth: '10.00' }) - expect(response.statusCode).toBe(302) - expect(response.headers.location).toEqual('/start') - }) + .post("/login/auth") + .send({ auth: "10.00" }); + expect(response.statusCode).toBe(302); + expect(response.headers.location).toEqual("/start"); + }); - const badRedirects = ['https%3A%2F%2Fevilcompany.com', 'evilcompany.com'] + const badRedirects = ["https%3A%2F%2Fevilcompany.com", "evilcompany.com"]; badRedirects.map(redirect => { test(`it throws a 500 error for a non-relative "redirect" query parameter link: "${redirect}"`, async () => { const response = await request(app) .post(`/login/auth?redirect=${redirect}`) - .send({ auth: '10.00' }) - expect(response.statusCode).toBe(500) + .send({ auth: "10.00" }); + expect(response.statusCode).toBe(500); expect(response.text).toMatch( - 'Error: [POST /login/auth] can only redirect to relative URLs', - ) - }) - }) - }) -}) + "Error: [POST /login/auth] can only redirect to relative URLs" + ); + }); + }); + }); +}); diff --git a/routes/offramp/offramp.controller.js b/routes/offramp/offramp.controller.js index 3bd95fe..4522ec6 100755 --- a/routes/offramp/offramp.controller.js +++ b/routes/offramp/offramp.controller.js @@ -6,12 +6,4 @@ module.exports = function(app) { app.get('/offramp/name', (req, res) => res.render('offramp/name', { data: req.session }), ) - - app.get('/offramp/residence', (req, res) => - res.render('offramp/residence', { data: req.session }), - ) - - app.get('/offramp/financial', (req, res) => - res.render('offramp/financial', { data: req.session }), - ) } \ No newline at end of file diff --git a/routes/partner/partner.controller.js b/routes/partner/partner.controller.js deleted file mode 100755 index a56a889..0000000 --- a/routes/partner/partner.controller.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = function(app) { - app.get('/partner/name', (req, res) => res.render('partner/name', { data: req.session || {} })) -} diff --git a/routes/partner/partner.spec.js b/routes/partner/partner.spec.js deleted file mode 100755 index 0af59ca..0000000 --- a/routes/partner/partner.spec.js +++ /dev/null @@ -1,9 +0,0 @@ -const request = require('supertest') -const app = require('../../app.js') - -describe('Test /partner responses', () => { - test.skip('it returns a 200 response for /partner/name', async () => { - const response = await request(app).get('/partner/name') - expect(response.statusCode).toBe(200) - }) -}) diff --git a/routes/personal/personal.controller.js b/routes/personal/personal.controller.js index 6a21d96..1ba4656 100755 --- a/routes/personal/personal.controller.js +++ b/routes/personal/personal.controller.js @@ -1,84 +1,26 @@ -const { checkSchema } = require('express-validator') -const { validateRedirect, checkErrors, doAuth } = require('./../../utils') -const { maritalStatusSchema, addressSchema, residenceSchema, nameSchema } = require('./../../formSchemas.js') +const { checkSchema } = require("express-validator"); +const { validateRedirect, checkErrors } = require("./../../utils"); +const { nameSchema } = require("./../../formSchemas.js"); module.exports = function(app) { - app.get('/personal/name', (req, res) => res.render('personal/name', { data: req.session })) + app.get("/personal/name", (req, res) => + res.render("personal/name", { data: req.session }) + ); app.post( - '/personal/name', + "/personal/name", validateRedirect, checkSchema(nameSchema), - checkErrors('personal/name'), - postName, - ) - app.get('/personal/address', (req, res) => res.render('personal/address', { data: req.session })) - app.get('/personal/address/edit', doAuth, (req, res) => - res.render('personal/address-edit', { data: req.session }), - ) - app.post( - '/personal/address/edit', - doAuth, - validateRedirect, - checkSchema(addressSchema), - checkErrors('personal/address-edit'), - postAddress, - ) - - app.get('/personal/residence', (req, res) => res.render('personal/residence')) - app.post( - '/personal/residence', - validateRedirect, - checkSchema(residenceSchema), - checkErrors('personal/residence'), - postResidence, - ) - - app.get('/personal/maritalStatus', (req, res) => - res.render('personal/maritalStatus', { data: req.session }), - ) - app.get('/personal/maritalStatus/edit', doAuth, (req, res) => - res.render('personal/maritalStatus-edit', { data: req.session }), - ) - app.post( - '/personal/maritalStatus/edit', - doAuth, - validateRedirect, - checkSchema(maritalStatusSchema), - checkErrors('personal/maritalStatus-edit'), - postMaritalStatus, - ) -} - -const postAddress = (req, res) => { - // copy all posted parameters, but remove the redirect - let addressData = Object.assign({}, req.body) - delete addressData.redirect - - req.session.personal.address = addressData - - return res.redirect(req.body.redirect) -} - -const postMaritalStatus = (req, res) => { - req.session.personal.maritalStatus = req.body.maritalStatus - - return res.redirect(req.body.redirect) -} - -const postResidence = (req, res) => { - if (req.body.residence !== 'Ontario') { - return res.redirect('/offramp/residence') - } - - return res.redirect(req.body.redirect) -} + checkErrors("personal/name"), + postName + ); +}; const postName = (req, res) => { - const name = req.body.name + const name = req.body.name; - if (name !== 'Yes') { - return res.redirect('/offramp/name') + if (name !== "Yes") { + return res.redirect("/offramp/name"); } - return res.redirect(req.body.redirect) -} + return res.redirect(req.body.redirect); +}; diff --git a/routes/personal/personal.spec.js b/routes/personal/personal.spec.js index 20f056c..2c533a4 100755 --- a/routes/personal/personal.spec.js +++ b/routes/personal/personal.spec.js @@ -1,175 +1,15 @@ -const request = require('supertest') -const cheerio = require('cheerio') -const app = require('../../app.js') -const API = require('../../api/index') - -describe('Test /personal responses', () => { - describe('Test /personal 200 responses', () => { - const urls = [ - '/personal/name', - '/personal/maritalStatus', - '/personal/maritalStatus/edit', - '/personal/residence', - '/personal/address', - '/personal/address/edit', - ] - - urls.map(url => { - test(`it returns a 200 response for the path: "${url}" path`, async () => { - const response = await request(app).get(url) - expect(response.statusCode).toBe(200) - }) - }) - }) - - describe('Test /personal/maritalStatus responses', () => { - test('it has Married selected by default', async () => { - const response = await request(app).get('/personal/maritalStatus') - const $ = cheerio.load(response.text) - expect($('td div').text()).toEqual('Single') - }) - - test('it checks the stored marital status by default for /personal/maritalStatus/edit path', async () => { - const user = API.getUser('A5G98S4K1') - const response = await request(app).get('/personal/maritalStatus/edit', { data: user }) - const $ = cheerio.load(response.text) - expect($('input[name=maritalStatus]:checked').val().toLowerCase).toEqual( - user.personal.maritalStatus.toLowerCase, - ) - }) - - test('it returns a 422 with no marital status', async () => { - const response = await request(app) - .post('/personal/maritalStatus/edit') - .send({ redirect: '/personal/maritalStatus' }) - expect(response.statusCode).toBe(422) - }) - - test('it returns a 422 with fake marital status', async () => { - const response = await request(app) - .post('/personal/maritalStatus/edit') - .send({ maritalStatus: 'cat lady', redirect: '/personal/maritalStatus' }) - expect(response.statusCode).toBe(422) - }) - - test('it returns a 302 with valid marital status', async () => { - const response = await request(app) - .post('/personal/maritalStatus/edit') - .send({ redirect: '/personal/maritalStatus', maritalStatus: 'Widowed' }) - expect(response.statusCode).toBe(302) - }) - }) - - describe('Test /personal/residence responses', () => { - test('it returns a 422 with no option selected', async () => { - const response = await request(app) - .post('/personal/residence') - .send({ redirect: '/personal/address' }) - expect(response.statusCode).toBe(422) - }) - - test('it returns a 302 when selecting unsupported province', async () => { - const response = await request(app) - .post('/personal/residence') - .send({ redirect: '/offramp/residence', residence: 'Alberta' }) - expect(response.headers.location).toEqual('/offramp/residence') - expect(response.statusCode).toBe(302) - }) - - test('it returns a 302 when selecting Ontario', async () => { - const response = await request(app) - .post('/personal/residence') - .send({ redirect: '/personal/address', residence: 'Ontario' }) - expect(response.headers.location).toEqual('/personal/address') - expect(response.statusCode).toBe(302) - }) - }) - - describe('Test /personal/address responses', () => { - let goodRequest = { - line1: 'Awesome Avenue', - city: 'Awesawa', - postalCode: 'H3L1Y4', - province: 'Ontario', - redirect: '/personal/address', - } - - const badRequests = [ - { - label: 'no streetAddress or city or postalCode or province', - firstErrorId: '#line1', - send: { - ...goodRequest, - ...{ line1: '', city: '', postalCode: '', province: '' }, - }, - }, - { - label: 'no streetAddress', - firstErrorId: '#line1', - send: { - ...goodRequest, - ...{ line1: '' }, - }, - }, - { - label: 'no city', - firstErrorId: '#city', - send: { - ...goodRequest, - ...{ city: '' }, - }, - }, - { - label: 'no postalCode', - firstErrorId: '#postalCode', - send: { - ...goodRequest, - ...{ postalCode: '' }, - }, - }, - { - label: 'bad postalCode', - firstErrorId: '#postalCode', - send: { - ...goodRequest, - ...{ postalCode: '0h3 N03' }, - }, - }, - { - label: 'no province', - firstErrorId: '#province', - send: { - ...goodRequest, - ...{ province: '' }, - }, - }, - { - label: 'bad province', - firstErrorId: '#province', - send: { - ...goodRequest, - ...{ province: 'Aurora' }, - }, - }, - ] - - - badRequests.map(badRequest => { - test(`it returns a 422 with: "${badRequest.label}"`, async () => { - const response = await request(app) - .post('/personal/address/edit') - .send(badRequest.send) - const $ = cheerio.load(response.text) - expect($(badRequest.firstErrorId).attr('autofocus')).toEqual('autofocus') - expect(response.statusCode).toBe(422) - }) - }) - - test('it returns a 302 with valid address', async () => { - const response = await request(app) - .post('/personal/address/edit') - .send(goodRequest) - expect(response.statusCode).toBe(302) - }) - }) -}) +const request = require("supertest"); +const cheerio = require("cheerio"); +const app = require("../../app.js"); +const API = require("../../api/index"); + +describe("Test /personal 200 responses", () => { + const urls = ["/personal/name"]; + + urls.map(url => { + test(`it returns a 200 response for the path: "${url}" path`, async () => { + const response = await request(app).get(url); + expect(response.statusCode).toBe(200); + }); + }); +}); diff --git a/utils/index.js b/utils/index.js index 81820bd..44ae4aa 100755 --- a/utils/index.js +++ b/utils/index.js @@ -1,5 +1,5 @@ -const API = require('./../api') -const { validationResult } = require('express-validator') +const API = require("./../api"); +const { validationResult } = require("express-validator"); /* original format is an array of error objects: https://express-validator.github.io/docs/validation-result-api.html @@ -17,13 +17,13 @@ const { validationResult } = require('express-validator') */ const errorArray2ErrorObject = (errors = []) => { return errors.array({ onlyFirstError: true }).reduce((map, obj) => { - map[obj.param] = obj - return map - }, {}) -} + map[obj.param] = obj; + return map; + }, {}); +}; /* Middleware */ -const oneHour = 1000 * 60 * 60 * 1 +const oneHour = 1000 * 60 * 60 * 1; /** * This request middleware checks for the "lang" query. @@ -32,14 +32,18 @@ const oneHour = 1000 * 60 * 60 * 1 * From this point onwards, all of the site's content will be in the user's preferred language. */ const checkLangQuery = function(req, res, next) { - let lang = req.query.lang - - if (lang === 'en' || lang === 'fr') { - res.cookie('lang', lang, { httpOnly: true, maxAge: oneHour, sameSite: 'strict' }) + let lang = req.query.lang; + + if (lang === "en" || lang === "fr") { + res.cookie("lang", lang, { + httpOnly: true, + maxAge: oneHour, + sameSite: "strict" + }); } - return next() -} + return next(); +}; /** * This request middleware checks if we are visiting a public path @@ -51,19 +55,19 @@ const checkLangQuery = function(req, res, next) { * that a user session exists whatever page you end up on. */ const checkPublic = function(req, res, next) { - const publicPaths = ['/', '/clear', '/start', '/login/code'] + const publicPaths = ["/", "/clear", "/start", "/login/code"]; if (publicPaths.includes(req.path)) { - return next() + return next(); } // check if user exists in session (ie, by checking for firstName) - const { personal: { firstName = null } = {} } = req.session + const { personal: { firstName = null } = {} } = req.session; if (!firstName) { - req.session = API.getUser('A5G98S4K1') + req.session = API.getUser("A5G98S4K1"); } - return next() -} + return next(); +}; /** * This request middleware is used to add an "auth" step to some of our pages @@ -82,18 +86,18 @@ const checkPublic = function(req, res, next) { */ const doAuth = function(req, res, next) { // if running tests, do nothing - if (process.env.NODE_ENV === 'test') { - return next() + if (process.env.NODE_ENV === "test") { + return next(); } // go to original url if "auth" is truthy - const { login: { auth = null } = {} } = req.session + const { login: { auth = null } = {} } = req.session; if (auth) { - return next() + return next(); } - return res.redirect(`/login/auth?redirect=${encodeURIComponent(req.path)}`) -} + return res.redirect(`/login/auth?redirect=${encodeURIComponent(req.path)}`); +}; /** * Middleware function that runs our error validation @@ -115,51 +119,36 @@ const doAuth = function(req, res, next) { */ const checkErrors = template => { return (req, res, next) => { - const errors = validationResult(req) + const errors = validationResult(req); // copy all posted parameters, but remove the redirect - let body = Object.assign({}, req.body) - delete body.redirect + let body = Object.assign({}, req.body); + delete body.redirect; if (!errors.isEmpty()) { return res.status(422).render(template, { data: req.session, body, - errors: errorArray2ErrorObject(errors), - }) + errors: errorArray2ErrorObject(errors) + }); } - return next() - } -} + return next(); + }; +}; //POST functions that handle setting the login data in the session and handle redirecting to the next page or sending an error to the client. //Note that this is not the only error validation, see routes defined above. const validateRedirect = (req, res, next) => { - let redirect = req.body.redirect || null + let redirect = req.body.redirect || null; if (!redirect) { - throw new Error(`[POST ${req.path}] 'redirect' parameter missing`) + throw new Error(`[POST ${req.path}] 'redirect' parameter missing`); } - return next() -} + return next(); +}; /* Pug filters */ -/** - * Accepts a string (assumed to be a SIN) - * If it is 9 characters long 9, this function returns a string with - * a space inserted after the 3rd character and the 6th character - * - * ie, "847339283" => "847 339 283" - * - * @param string text a 9-character string assumed to be a social insurance number - */ -const SINFilter = text => { - if (text.length === 9) { - text = text.slice(0, 3) + ' ' + text.slice(3, 6) + ' ' + text.slice(6) - } - return text -} /** * @param {Object} obj the obj we're passing, most often 'data' @@ -168,55 +157,27 @@ const SINFilter = text => { * pass as hasData(data, 'personal.maritalStatus') */ const hasData = (obj, key) => { - return key.split('.').every(x => { + return key.split(".").every(x => { if ( - typeof obj != 'object' || + typeof obj != "object" || obj === null || !obj.hasOwnProperty(x) || // eslint-disable-line no-prototype-builtins obj[x] === null || - obj[x] === '' + obj[x] === "" ) { - return false + return false; } - obj = obj[x] - return true - }) -} - -const currencyFilter = (number, fractionDigits = 2) => { - const amount = Number(number) - - return amount.toLocaleString('en-US', { - minimumFractionDigits: fractionDigits, - maximumFractionDigits: fractionDigits, - }) -} - -const sortByLineNumber = (...objToSort) => { - //take all the objects, make them into one big object - const superObj = Object.assign({}, ...objToSort) - - //filter down the object into an array of objects, - //but only the objects with the line property - const filteredObj = Object.entries(superObj).filter(obj => { - return typeof obj[1] === 'object' && obj[1] !== null && obj[1] !== undefined && obj[1].hasOwnProperty('line') - }) - - //sort the array of objects according to the line value - const sortedArrayObj = filteredObj.map(obj => obj[1]).sort((a,b) => a.line - b.line) - - return sortedArrayObj -} + obj = obj[x]; + return true; + }); +}; module.exports = { errorArray2ErrorObject, validateRedirect, checkErrors, doAuth, - SINFilter, hasData, checkPublic, - currencyFilter, - sortByLineNumber, - checkLangQuery, -} + checkLangQuery +}; diff --git a/utils/index.spec.js b/utils/index.spec.js index 7546fe4..ffd6452 100755 --- a/utils/index.spec.js +++ b/utils/index.spec.js @@ -1,54 +1,24 @@ -const { SINFilter, hasData } = require('./index') -const API = require('./../api') - -describe('Test SINFilter', () => { - const sinFilterUnchanged = ['1', '', '1234567890', '12345678'] - sinFilterUnchanged.map(value => { - test(`returns value for "${value}"`, () => { - expect(SINFilter(value)).toEqual(value) - }) - }) - - const sinFilterChanged = [['123456789', '123 456 789'], ['ABCDEFGHI', 'ABC DEF GHI']] - sinFilterChanged.map(values => { - test(`returns "${values[1]}" for "${values[0]}"`, () => { - expect(SINFilter(values[0])).toEqual(values[1]) - }) - }) -}) - -describe('Test hasData function', () => { - const user = API.getUser('A5G98S4K1') - - test('returns true for maritalStatus', () => { - expect(hasData(user, 'personal.maritalStatus')).toBe(true) - }) - - test('returns false for property that does not exist', () => { - expect(hasData(user, 'personal.middleName')).toBe(false) - }) - - test('returns true for city in address', () => { - expect(hasData(user, 'personal.address.city')).toBe(true) - }) - - test('returns false for non-object', () => { - expect(hasData('this is not an object', 'personal.address.city')).toBe(false) - }) - - test('returns false for null object', () => { - expect(hasData(null, 'personal.address.city')).toBe(false) - }) - - test('returns false for empty object', () => { - expect(hasData({}, 'personal.address.city')).toBe(false) - }) - - test('returns false for empty string', () => { - expect(hasData({ obj: { string: '' } }, 'obj.string')).toBe(false) - }) - - test('returns true for disabilityClaim', () => { - expect(hasData(user, 'deductions.disabilityClaim')).toBe(false) - }) -}) +const { hasData } = require("./index"); +const API = require("./../api"); + +describe("Test hasData function", () => { + const user = API.getUser("A5G98S4K1"); + + test("returns false for non-object", () => { + expect(hasData("this is not an object", "personal.address.city")).toBe( + false + ); + }); + + test("returns false for null object", () => { + expect(hasData(null, "personal.address.city")).toBe(false); + }); + + test("returns false for empty object", () => { + expect(hasData({}, "personal.address.city")).toBe(false); + }); + + test("returns false for empty string", () => { + expect(hasData({ obj: { string: "" } }, "obj.string")).toBe(false); + }); +}); diff --git a/views/_includes/offramp-bullets.pug b/views/_includes/offramp-bullets.pug deleted file mode 100755 index e88fdef..0000000 --- a/views/_includes/offramp-bullets.pug +++ /dev/null @@ -1,4 +0,0 @@ -ul - li #{__('Visit a free tax clinic near you. ')} #{__('You can have a volunteer help you submit your taxes.')} - li #{__('Contact CRA at')} #[a(href="tel:123-456-7890") (123) 456-7890] #{__('for help')} - li #{__('File your taxes with')} #{__('other NETFILE software certified by CRA')} diff --git a/views/confirmation/confirmation.pug b/views/confirmation/confirmation.pug index 2189eba..c102fa0 100755 --- a/views/confirmation/confirmation.pug +++ b/views/confirmation/confirmation.pug @@ -17,25 +17,4 @@ block content th #{__('Confirmation number')} tbody tr - td 5H3P9IO5816 - - p #{__('Use this confirmation number if you need to contact CRA for further information or for additional help with your tax return.')} - - a.button-link(href='#' role='button' draggable='false') #{__('Print a summary of your tax return')} - - div - - p #{__('Your Notice of Assessment is an official CRA communication that confirms that you’ve filed your taxes. It also contains the details of your refund or balance owing. Please read this document carefully.')} - - a.button-link(href='#' role='button' draggable='false') #{__('Download your Notice of Assessment')} - - div - h3 #{__('Do you have questions?')} - - p #{__('Now that your return is filed, you should be all set for the year.')} - p #{__('However, if you still have further questions, there are several ways to get help:')} - ul - li #{__('Speak to someone at your nearest tax clinic')} - li #{__('Go online to')} #{__('find a free tax clinic in your area')} - li #{__('Speak to a CRA agent by calling')} #[a(href="tel:123-456-7890") (123) 456-7890] - + td 5H3P9IO5816 \ No newline at end of file diff --git a/views/confirmation/review.pug b/views/confirmation/review.pug index 90d3b3d..1068487 100755 --- a/views/confirmation/review.pug +++ b/views/confirmation/review.pug @@ -3,13 +3,6 @@ include ../_includes/yesNoRadios block variables -var title = __('Review and file tax return') - -var benefits = hasData(data, 'benefits') ? data.benefits : {} - -var totalBenefits = hasData(data, 'benefits.totalBenefits.amount') ? data.benefits.totalBenefits.amount : 0 - -var incomes = hasData(data, 'financial.incomes') ? data.financial.incomes : {} - -var taxes = hasData(data, 'financial.taxes') ? data.financial.taxes : {} - -var refund = hasData(data, 'refund') ? data.refund : {} - -var totalRefund = hasData(data, 'refund.totalRefund') ? data.refund.totalRefund : 0 - -var refundLines = sortByLineNumber(data.deductions, taxes, incomes, refund) -var count = 1; @@ -21,49 +14,6 @@ block content p #{__('This is an overview of your projected tax return, and all the benefits you will receive when you file for the current tax year.')} p #{__('Take one final look before continuing. If something looks incorrect, please')} #[a(href="https://www.canada.ca/en/revenue-agency/corporate/contact-information/telephone-numbers.html") #{__('contact CRA')}] #{__('before filing.')} - div - .breakdown-table - h2.breakdown-table__heading - span #{__('Your annual benefits')} - span $#{currencyFilter(totalBenefits)} - - p.breakdown-table__subheading #{__('Detailed breakdown of benefits')} - - dl.breakdown-table-data - each benefit in benefits - if benefit.name !== "totalBenefits" - .breakdown-table__row - dt.breakdown-table__row-key #{__(`${benefit.name}`)} - dd.breakdown-table__row-value $#{currencyFilter(benefit.amount)} - - .breakdown-table__row.breakdown-table__row--summary - dt.breakdown-table__row-key #{__('Total Benefits')} - dd.breakdown-table__row-value $#{currencyFilter(totalBenefits)} - - div - .breakdown-table - h2.breakdown-table__heading - span #{__('Your projected refund')} - span +$#{currencyFilter(totalRefund.amount)} - - p.breakdown-table__subheading #{__('Detailed breakdown of tax refund')} - - dl.breakdown-table-data - each refundLine in refundLines - -var lineNumber = refundLine.multiLine ? refundLine.multiLine : refundLine.line - .breakdown-table__row( - class={ - ['breakdown-table__row--summary space-row']: refundLine.name === "Total Refund", - ['space-row']: count === 5 || count === 6 || count === 7 || count === 9 - } - ) - dt.breakdown-table__row-key #{__(`${refundLine.name} (${lineNumber})`)} - dd.breakdown-table__row-value $#{currencyFilter(refundLine.amount)} - - - count++ - - - form.cra-form(method='post') div(class={['has-error']: errors && errors.review}) .multiple-choice.multiple-choice--checkboxes diff --git a/views/deductions/climate-action-incentive.pug b/views/deductions/climate-action-incentive.pug deleted file mode 100755 index defb12a..0000000 --- a/views/deductions/climate-action-incentive.pug +++ /dev/null @@ -1,26 +0,0 @@ -extends ../base -include ../_includes/yesNoRadios - -block variables - -var title = __('Climate Action Incentive') - -var climateActionIncentiveIsRural = hasData(data, 'deductions.climateActionIncentiveIsRural') ? data.deductions.climateActionIncentiveIsRural : '' - -block content - - h1 #{title} - - div - p #{__('You’re eligible for the Climate Action Incentive, which you will receive automatically.')} - p #{__('There is an additional 10% credit for residents of small and rural communities')} - - form.cra-form(method='post') - +yesNoRadios('climateActionIncentiveIsRural', climateActionIncentiveIsRural, 'Did you live in a small and rural community in December 2018?', errors) - - div - details. - #{__('How do I know if I live in a small and rural community')} -

#{__('You live in a small or rural community if you')} #{__('do not')} #{__('live in these areas: Ottawa, Kingston, Belleville, Peterborough, Oshawa, Toronto, Hamilton, St. Catharines-Niagara, Kitchener-Cambridge-Waterloo, Brantford, Guelph, London, Windsor, Barrie, Sudbury, or Thunder Bay.')}

- - input#redirect(name='redirect', type='hidden', value='/review') - - +formButtons() diff --git a/views/deductions/donations-amount.pug b/views/deductions/donations-amount.pug deleted file mode 100755 index 6e827bb..0000000 --- a/views/deductions/donations-amount.pug +++ /dev/null @@ -1,19 +0,0 @@ -extends ../base - -block variables - -var title = __('Enter your charitable donations') - -var donationsAmount = hasData(data, 'deductions.donationsAmount') & data.deductions.donationsAmount !== 0 ? data.deductions.donationsAmount : '' - -block content - - h1 #{title} - - div - p #{__('Please enter your charitable donations into the fields below.')} - - form.cra-form(method='post') - +textInput('Total donations made to registered charities')(class='w-1-2 input-with-unit' name='donationsAmount' placeholder='0.00' aria-labelledby='donationsAmount__unit donationsAmount__label' value=donationsAmount) - - input#redirect(name='redirect', type='hidden', value='/trillium/rent/amount') - - +formButtons('Continue', '/deductions/donations') diff --git a/views/deductions/donations.pug b/views/deductions/donations.pug deleted file mode 100755 index bb40d9b..0000000 --- a/views/deductions/donations.pug +++ /dev/null @@ -1,20 +0,0 @@ -extends ../base -include ../_includes/yesNoRadios - -block variables - -var title = __('Deduct your charitable donations') - -var donationsClaim = hasData(data, 'deductions.donationsClaim') ? data.deductions.donationsClaim : '' - -block content - - h1 #{title} - - div - p #{__('Did you make any charitable donations in 2018?')} - - form.cra-form(method='post') - +yesNoRadios('donationsClaim', donationsClaim, 'Did you make charitable donations?', errors) - - input#redirect(name='redirect', type='hidden', value='/trillium/rent/amount') - - +formButtons() diff --git a/views/deductions/medical-amount.pug b/views/deductions/medical-amount.pug deleted file mode 100755 index 54d31c8..0000000 --- a/views/deductions/medical-amount.pug +++ /dev/null @@ -1,24 +0,0 @@ -extends ../base - -block variables - -var title = __('Claim medical expenses') - -var medicalClaim = hasData(data, 'deductions.medicalClaim') ? data.deductions.medicalClaim : '' - -block content - - h1 #{title} - - div - p #{__('You can claim medical expenses for your self, spouse or common-law partner, and dependent children born after 2001.')} - - form.cra-form(method='post') - +textInput('Enter the total cost of medical expenses for your self, spouse, and dependent children born after 2001')(class='w-1-2 input-with-unit' name='medicalAmount' placeholder='0.00' aria-labelledby='medicalAmount__unit medicalAmount__label' value=medicalAmount) - - input#redirect(name='redirect', type='hidden', value='/deductions/political') - - div - details. - #{__('Learn more about eligible medical expenses')} -

#{__('Eligible medical expenses can include specialized equipment, accessibility devices, etc. For more information, please refer to ')} #{__(`the CRA's guide to eligible medical expenses`)}.

- - +formButtons('Continue', '/deductions/medical') diff --git a/views/deductions/medical.pug b/views/deductions/medical.pug deleted file mode 100755 index dc8c3ca..0000000 --- a/views/deductions/medical.pug +++ /dev/null @@ -1,20 +0,0 @@ -extends ../base -include ../_includes/yesNoRadios - -block variables - -var title = __('Medical expenses') - -var medicalClaim = hasData(data, 'deductions.medicalClaim') ? data.deductions.medicalClaim : '' - -block content - - h1 #{title} - - div - p #{__('You can claim medical expenses for your self, spouse or common-law partner, and dependent children born after 2001.')} - - form.cra-form(method='post') - +yesNoRadios('medicalClaim', medicalClaim, 'Would you like to claim medical expenses?', errors) - - input#redirect(name='redirect', type='hidden', value='/deductions/political') - - +formButtons() diff --git a/views/deductions/political-amount.pug b/views/deductions/political-amount.pug deleted file mode 100755 index eb2013d..0000000 --- a/views/deductions/political-amount.pug +++ /dev/null @@ -1,22 +0,0 @@ -extends ../base - -block variables - -var title = __('Enter your political contributions') - -var politicalFederalAmount = hasData(data, 'deductions.politicalFederalAmount') & data.deductions.politicalFederalAmount !== 0 ? data.deductions.politicalFederalAmount : '' - -var politicalProvincialAmount = hasData(data, 'deductions.politicalProvincialAmount') & data.deductions.politicalProvincialAmount !== 0 ? data.deductions.politicalProvincialAmount : '' - -block content - - h1 #{title} - - div - p #{__('Please enter your political contributions into the fields below.')} - - form.cra-form(method='post') - +textInput('Total federal contributions')(class='w-1-2 input-with-unit' name='politicalFederalAmount' placeholder='0.00' aria-labelledby='politicalFederalAmount__unit politicalFederalAmount__label' value=politicalFederalAmount) - - +textInput('Total provincial contributions')(class='w-1-2 input-with-unit' name='politicalProvincialAmount' placeholder='0.00' aria-labelledby='politicalProvincialAmount__unit politicalProvincialAmount__label' value=politicalProvincialAmount) - - input#redirect(name='redirect', type='hidden', value='/deductions/donations') - - +formButtons('Continue', '/deductions/political') diff --git a/views/deductions/political.pug b/views/deductions/political.pug deleted file mode 100755 index a72a495..0000000 --- a/views/deductions/political.pug +++ /dev/null @@ -1,20 +0,0 @@ -extends ../base -include ../_includes/yesNoRadios - -block variables - -var title = __('Political contributions') - -var politicalClaim = hasData(data, 'deductions.politicalClaim') ? data.deductions.politicalClaim : '' - -block content - - h1 #{title} - - div - p #{__('Did you make any political contributions in 2018?')} - - form.cra-form(method='post') - +yesNoRadios('politicalClaim', politicalClaim, 'Deduct political contributions?', errors) - - input#redirect(name='redirect', type='hidden', value='/deductions/donations') - - +formButtons() diff --git a/views/deductions/rrsp-amount.pug b/views/deductions/rrsp-amount.pug deleted file mode 100755 index 0a9fe2d..0000000 --- a/views/deductions/rrsp-amount.pug +++ /dev/null @@ -1,19 +0,0 @@ -extends ../base - -block variables - -var title = __('Enter your RRSP contributions') - -var rrspAmount = hasData(data, 'deductions.rrspAmount.amount') && data.deductions.rrspAmount.amount !== 0 ? data.deductions.rrspAmount.amount : '' - -block content - - h1 #{title} - - div - p #{__('Please enter your RRSP contributions before March 1, 2019.')} - - form.cra-form(method='post') - +textInput('Total RRSP contributions')(class='w-1-2 input-with-unit' name='rrspAmount' placeholder='0.00' aria-labelledby='rrspAmount__unit rrspAmount__label' value=rrspAmount autofocus) - - input#redirect(name='redirect', type='hidden', value='/personal/maritalStatus') - - +formButtons('Continue', '/deductions/rrsp') diff --git a/views/deductions/rrsp.pug b/views/deductions/rrsp.pug deleted file mode 100755 index c64d382..0000000 --- a/views/deductions/rrsp.pug +++ /dev/null @@ -1,20 +0,0 @@ -extends ../base -include ../_includes/yesNoRadios - -block variables - -var title = __('Deduct your RRSP contributions') - -var rrspClaim = hasData(data, 'deductions.rrspClaim') ? data.deductions.rrspClaim : '' - -block content - - h1 #{title} - - div - p #{__('If you made RRSP contributions before March 1, 2019, you can deduct them from your total income on your taxes this year.')} - - form.cra-form(method='post') - +yesNoRadios('rrspClaim', rrspClaim, 'Did you contribute to an RRSP?', errors) - - input#redirect(name='redirect', type='hidden', value='/personal/maritalStatus') - - +formButtons() diff --git a/views/deductions/trillium-energy-amount.pug b/views/deductions/trillium-energy-amount.pug deleted file mode 100755 index 58778ca..0000000 --- a/views/deductions/trillium-energy-amount.pug +++ /dev/null @@ -1,21 +0,0 @@ -extends ../base - -block variables - -var title = __('Home energy costs on a reserve') - -var trilliumEnergyAmount = hasData(data, 'deductions.trilliumEnergyAmount') ? data.deductions.trilliumEnergyAmount : '0' - -block content - - h1 #{title} - - div - p #{__('Please enter the home energy costs paid for your principal residence on a reserve in Ontario in 2018.')} - - p #{__('Leave the field as')} 0, #{__('if this doesn’t apply to you or if you don’t have the receipts to verify this information later.')} - - form.cra-form(method='post') - +textInput('Home energy costs on a reserve in 2018')(class='w-1-2 input-with-unit' name='trilliumEnergyAmount' placeholder='0.00' aria-labelledby='trilliumEnergyAmount__unit trilliumEnergyAmount__label' value=trilliumEnergyAmount) - - input#redirect(name='redirect', type='hidden', value='/trillium/longTermCare/amount') - - +formButtons('Continue') diff --git a/views/deductions/trillium-longTermCare-amount.pug b/views/deductions/trillium-longTermCare-amount.pug deleted file mode 100755 index 109bd0a..0000000 --- a/views/deductions/trillium-longTermCare-amount.pug +++ /dev/null @@ -1,21 +0,0 @@ -extends ../base - -block variables - -var title = __('Public long-term care home costs') - -var trilliumLongTermCareAmount = hasData(data, 'deductions.trilliumLongTermCareAmount') ? data.deductions.trilliumLongTermCareAmount : '0' - -block content - - h1 #{title} - - div - p #{__('Please enter the total amount paid for accommodation in a public or non-profit long-term care home in 2018.')} - - p #{__('Leave the field as')} 0, #{__('if this doesn’t apply to you or if you don’t have the receipts to verify this information later.')} - - form.cra-form(method='post') - +textInput('Accommodation costs in 2018')(class='w-1-2 input-with-unit' name='trilliumLongTermCareAmount' placeholder='0.00' aria-labelledby='trilliumLongTermCareAmount__unit trilliumLongTermCareAmount__label' value=trilliumLongTermCareAmount) - - input#redirect(name='redirect', type='hidden', value='/deductions/climate-action-incentive') - - +formButtons('Continue') diff --git a/views/deductions/trillium-propertyTax-amount.pug b/views/deductions/trillium-propertyTax-amount.pug deleted file mode 100755 index 02fb07e..0000000 --- a/views/deductions/trillium-propertyTax-amount.pug +++ /dev/null @@ -1,21 +0,0 @@ -extends ../base - -block variables - -var title = __('Enter property tax paid in 2018') - -var trilliumPropertyTaxAmount = hasData(data, 'deductions.trilliumPropertyTaxAmount') ? data.deductions.trilliumPropertyTaxAmount : '0' - -block content - - h1 #{title} - - div - p #{__('Please enter the total property tax paid for your principal residence in 2018.')} - - p #{__('Leave the field as')} 0, #{__('if you paid no property tax in 2018 or if you don’t have the receipts to verify this information later.')} - - form.cra-form(method='post') - +textInput('Total property tax in 2018')(class='w-1-2 input-with-unit' name='trilliumPropertyTaxAmount' placeholder='0.00' aria-labelledby='trilliumPropertyTaxAmount__unit trilliumPropertyTaxAmount__label' value=trilliumPropertyTaxAmount) - - input#redirect(name='redirect', type='hidden', value='/trillium/studentResidence') - - +formButtons('Continue') diff --git a/views/deductions/trillium-rent-amount.pug b/views/deductions/trillium-rent-amount.pug deleted file mode 100755 index d3c000a..0000000 --- a/views/deductions/trillium-rent-amount.pug +++ /dev/null @@ -1,23 +0,0 @@ -extends ../base - -block variables - -var title = __('Enter rent paid in 2018') - -var trilliumRentAmount = hasData(data, 'deductions.trilliumRentAmount') ? data.deductions.trilliumRentAmount : '0' - -block content - - h1 #{title} - - div - p #{__('To get the most out of your')} #{__('Ontario Trillium Benefit')}, #{__('you can enter the amount you paid in rent in the current tax year.')} - - p #{__('Enter the')} #{__('total annual rent')}, #{__('you paid for your main residence (including a private long-term care home) in 2018.')} - - p #{__('Leave the field as')} 0, #{__('if you paid no rent in 2018 or if you don’t have the receipts to verify this information later.')} - - form.cra-form(method='post') - +textInput('Total annual rent in 2018')(class='w-1-2 input-with-unit' name='trilliumRentAmount' placeholder='0.00' aria-labelledby='trilliumRentAmount__unit trilliumRentAmount__label' value=trilliumRentAmount) - - input#redirect(name='redirect', type='hidden', value='/trillium/propertyTax/amount') - - +formButtons('Continue') diff --git a/views/deductions/trillium-studentResidence.pug b/views/deductions/trillium-studentResidence.pug deleted file mode 100755 index 75e7308..0000000 --- a/views/deductions/trillium-studentResidence.pug +++ /dev/null @@ -1,17 +0,0 @@ -extends ../base -include ../_includes/yesNoRadios - -block variables - -var title = __('Designated student residence') - -var trilliumStudentResidence = !hasData(data, 'deductions.trilliumStudentResidence') ? null : data.deductions.trilliumStudentResidence === true ? 'Yes' : 'No' - -block content - - h1 #{title} - - form.cra-form(method='post') - +yesNoRadios('trilliumStudentResidence', trilliumStudentResidence, 'Did you live in a designated student residence in 2018?', errors) - - input#redirect(name='redirect', type='hidden', value='/trillium/energy/amount') - - +formButtons() diff --git a/views/dependants/children.pug b/views/dependants/children.pug deleted file mode 100755 index 12a0d1a..0000000 --- a/views/dependants/children.pug +++ /dev/null @@ -1,11 +0,0 @@ -extends ../base - -block variables - -var title = 'Children stub page' - -block content - - h1 #{title} - - - p Please enter Children info diff --git a/views/financial/income.pug b/views/financial/income.pug deleted file mode 100755 index 6b27492..0000000 --- a/views/financial/income.pug +++ /dev/null @@ -1,63 +0,0 @@ -extends ../base -include ../_includes/yesNoRadios - -block variables - -var title = __('Confirm your income information') - -var incomeSources = hasData(data, 'financial.incomeSources') ? data.financial.incomeSources : {} - -var taxes = hasData(data, 'financial.taxes') ? data.financial.taxes : {} - -var totalIncome = hasData(data, 'financial.incomes.totalIncome') ? data.financial.incomes.totalIncome : 0 - -var totalTax = hasData(data, 'financial.totalTax') ? data.financial.totalTax : 0 - -var year = new Date().getFullYear()-1 - -block content - - h1 #{title} - - div - p #{__(`Here’s what CRA knows about your income for the current tax year (filing for ${year}). Additional claims and deductions can be made afterwards.`)} - - if incomeSources - .breakdown-table - h2.breakdown-table__heading - span #{__(`Total income earned in ${year}`)} - span $#{currencyFilter(totalIncome.amount, 0)} - - p.breakdown-table__subheading #{__(`Detailed breakdown of income earned in ${year}`)} - - dl.breakdown-table-data - each income in incomeSources - .breakdown-table__row - dt.breakdown-table__row-key #{income.name} #{__('Total Income')} - dd.breakdown-table__row-value $#{currencyFilter(income.total)} - - .breakdown-table__row.breakdown-table__row--summary - dt.breakdown-table__row-key #{__(`Total Income for ${year}`)} - dd.breakdown-table__row-value $#{currencyFilter(totalIncome.amount)} - - .breakdown-table - h2.breakdown-table__heading - span #{__('Total tax')} - span.breakdown-table__heading $#{currencyFilter(totalTax, 0)} - - p.breakdown-table__subheading #{__(`Detailed breakdown of taxes paid in ${year}`)} - - dl.breakdown-table-data - each tax in taxes - .breakdown-table__row - dt.breakdown-table__row-key #{__(`${tax.name.replace('Net ', '')} deduction`)} - dd.breakdown-table__row-value $#{currencyFilter(tax.amount)} - - .breakdown-table__row.breakdown-table__row--summary - dt.breakdown-table__row-key #{__(`Total tax paid for ${year}`)} - dd.breakdown-table__row-value $#{currencyFilter(totalTax)} - - form.cra-form(method='post') - +yesNoRadios('confirmIncome', null, 'Is this information correct?', errors) - .no-info - .no-info__wrapper - p #{__('If this information doesn’t match your records, you can’t change it here.')} - p #{__('You should not use this service to file income information you believe to be incorrect.')} - - input#redirect(name='redirect', type='hidden', value='/deductions/rrsp') - - +formButtons() \ No newline at end of file diff --git a/views/login/code.pug b/views/login/code.pug index e57f5d6..82a0167 100755 --- a/views/login/code.pug +++ b/views/login/code.pug @@ -19,6 +19,6 @@ block content #{__('Help with personal access code')}

#{__('Your code is on the personally-addressed letter.')}

- input#redirect(name='redirect', type='hidden', value='/login/sin') + input#redirect(name='redirect', type='hidden', value='/personal/name') +formButtons() diff --git a/views/login/dateOfBirth.pug b/views/login/dateOfBirth.pug deleted file mode 100755 index fd6104d..0000000 --- a/views/login/dateOfBirth.pug +++ /dev/null @@ -1,27 +0,0 @@ -extends ../base - -block variables - -var title = __('Enter your date of birth') - -var dateOfBirth = hasData(body, 'dateOfBirth') ? body.dateOfBirth : '' - -block content - - h1 #{title} - - div - p #{__('Thanks!')} #{__('We just need one more piece of information to authenticate you.')} - - p #{__('Please enter your date of birth in the field below.')} - - div - form.cra-form(method='post') - div(class={['has-error']: errors && errors.dateOfBirth}) - label(for='dateOfBirth') #{__('Date of Birth')} - span.cra-form-message #{__('For Example:')} #{data.personal.dateOfBirth} - if errors - +validationMessage(errors.dateOfBirth.msg, 'dateOfBirth') - input.w-3-4#dateOfBirth(name='dateOfBirth', autofocus, type='text', value=dateOfBirth, autocomplete='off' aria-describedby=(errors && errors.dateOfBirth ? 'dateOfBirth-error' : false)) - - input#redirect(name='redirect', type='hidden', value='/personal/name') - - +formButtons() diff --git a/views/login/sin.pug b/views/login/sin.pug deleted file mode 100755 index 161b399..0000000 --- a/views/login/sin.pug +++ /dev/null @@ -1,32 +0,0 @@ -extends ../base -include ../_includes/banner - -block variables - -var title = __('Enter your Social Insurance Number (SIN)') - -var sin = hasData(body, 'sin') ? body.sin : '' - -block content - - h1 #{title} - - +banner('check') - p #{__('Your access code was validated!')} - - if data.personal - h2 #{__('Thanks,')} #{data.personal.firstName} #{data.personal.lastName}! - - p #{__('Now that we have your personal code, we need some additional information in order to verify that it’s you.')} - - p #{__('Please enter your Social Insurance Number (SIN) in the field below.')} - - form.cra-form(method='post') - div(class={['has-error']: errors && errors.sin}) - label(for='sin') #{__('Social Insurance Number')} - span.cra-form-message #{__('For Example:')} #{SINFilter(data.personal.sin)} - if errors - +validationMessage(errors.sin.msg, 'sin') - input.w-3-4#sin(name='sin', autofocus, type='text', value=sin, autocomplete='off' aria-describedby=(errors && errors.sin ? 'sin-error' : false)) - - input#redirect(name='redirect', type='hidden', value='/login/dateOfBirth') - - +formButtons() diff --git a/views/offramp/financial.pug b/views/offramp/financial.pug deleted file mode 100755 index cbddccc..0000000 --- a/views/offramp/financial.pug +++ /dev/null @@ -1,17 +0,0 @@ -extends ../base -include ../_includes/banner - -block variables - -var title = __('The income we have on file does not match your records') - -block content - - h1 #{title} - - .offramp - p #{__('If your records don’t match the income information displayed earlier, or you believe it to be incorrect, you shouldn’t use this service to file your taxes.')} - - div - p #{__('There are also other free and secure ways to file your taxes:')} - include ../_includes/offramp-bullets - a.button-link(href='/financial/income') #{__('Go back')} diff --git a/views/offramp/name.pug b/views/offramp/name.pug index d47b6cf..e6b4c3c 100755 --- a/views/offramp/name.pug +++ b/views/offramp/name.pug @@ -12,5 +12,4 @@ block content p #{__('Without your correct name on file, you can’t file your taxes using this online service. You can still file using the Claim Tax Benefits service – follow the instructions on page X of the paper package we mailed to you.')} div - p #{__('There are also other free and secure ways to file your taxes:')} - include ../_includes/offramp-bullets \ No newline at end of file + p #{__('There are also other free and secure ways to file your taxes:')} \ No newline at end of file diff --git a/views/offramp/offramp.pug b/views/offramp/offramp.pug index 2619220..2a9d0bc 100755 --- a/views/offramp/offramp.pug +++ b/views/offramp/offramp.pug @@ -13,9 +13,3 @@ block content div p #{__('To finish filing your taxes for 2018, you will need to do one of the following:')} - ul - li #{__('Use the paper form enclosed in the Claim Tax Benefits package you received in the mail')} - li #{__('Visit a free tax clinic near you. ')} #{__('You can have a volunteer help you submit your taxes.')} - li #{__('Contact CRA at')} #[a(href="tel:123-456-7890") (123) 456-7890] #{__('for help')} - li #{__('File your taxes with')} #{__('other NETFILE software certified by CRA')} - diff --git a/views/offramp/residence.pug b/views/offramp/residence.pug deleted file mode 100755 index cfe04a4..0000000 --- a/views/offramp/residence.pug +++ /dev/null @@ -1,16 +0,0 @@ -extends ../base -include ../_includes/banner - -block variables - -var title = __('This service is only available to residents of Ontario') - -block content - - h1 #{title} - - div - p #{__('Since you weren’t a resident of Ontario on December 31, 2018, you can’t use this service to file your taxes.')} - - div - p #{__('There are also other free and secure ways to file your taxes:')} - include ../_includes/offramp-bullets diff --git a/views/partner/name.pug b/views/partner/name.pug deleted file mode 100755 index 1d3e914..0000000 --- a/views/partner/name.pug +++ /dev/null @@ -1,11 +0,0 @@ -extends ../base - -block variables - -var title = 'partner’s name stub page' - -block content - - h1 #{title} - - - p Please enter Partner's name diff --git a/views/personal/address-edit.pug b/views/personal/address-edit.pug deleted file mode 100755 index 93eadb3..0000000 --- a/views/personal/address-edit.pug +++ /dev/null @@ -1,54 +0,0 @@ -extends ../base - -block variables - -var title = __('Change your mailing address') - -var aptNumber = hasData(body, 'line2') ? body.line2 : hasData(data, 'personal.address.line2') ? data.personal.address.line2 : '' - -var streetAddress = hasData(body, 'line1') ? body.line1 : hasData(data, 'personal.address.line1') ? data.personal.address.line1 : '' - -var city = hasData(body, 'city') ? body.city : hasData(data, 'personal.address.city') ? data.personal.address.city : '' - -var postalCode = hasData(body, 'postalCode') ? body.postalCode : hasData(data, 'personal.address.postalCode') ? data.personal.address.postalCode : '' - -var province = hasData(body, 'province') ? body.province : hasData(data, 'personal.address.province') ? data.personal.address.province : '' - - -block content - - h1 #{title} - - div - p #{__('Please enter the correct mailing address information below. If a letter is sent to this address, you must be able to receive it.')} - - div - form.cra-form.cra-form--lg(method='post') - h2 #{__('Your mailing address')} - - +textInput('Street address', ['w-3-4','d--ib'])(class='w-3-4', value=streetAddress, name='line1' autofocus=(!errors || errors && firstError.param === 'line1' ? true : false)) - - +textInput('Apartment number', 'w-1-2', 'Optional')(class='w-3-4', value=aptNumber name='line2') - - +textInput('City', 'w-1-2')(class='w-3-4', value=city name='city') - - +textInput('Postal Code', ['w-1-2'], 'For Example: K2R 3Z9')(class='w-3-4' name='postalCode' value=postalCode) - - .w-1-2(class={['has-error']: errors && errors.province}) - label(for='province') #{__('Province')} - if errors && errors.province - +validationMessage(errors.province.msg, 'province') - select.w-3-4#province(name='province' aria-describedby=(errors && errors.province ? 'province-error' : false) autofocus=(errors && errors[Object.keys(errors)[0]].param === 'province'? true : false)) - if !province - option(disabled='', selected='selected', value='') -- select a province -- - option(value='Alberta' selected=province == 'Alberta') #{__('Alberta')} - option(value='British Columbia' selected=province == 'British Columbia') #{__('British Columbia')} - option(value='Manitoba' selected=province == 'Manitoba') #{__('Manitoba')} - option(value='New Brunswick' selected=province == 'New Brunswick') #{__('New Brunswick')} - option(value='Newfoundland And Labrador' selected=province =='Newfoundland And Labrador') #{__('Newfoundland and Labrador')} - option(value='Northwest Territories' selected=province =='Northwest Territories') #{__('Northwest Territories')} - option(value='Nova Scotia' selected=province =='Nova Scotia') #{__('Nova Scotia')} - option(value='Nunavut' selected=province =='Nunavut') #{__('Nunavut')} - option(value='Ontario' selected=province == 'Ontario') #{__('Ontario')} - option(value='Prince Edward Island' selected=province =='Prince Edward Island') #{__('Prince Edward Island')} - option(value='Quebec' selected=province =='Quebec') #{__('Quebec')} - option(value='Saskatchewan' selected=province =='Saskatchewan') #{__('Saskatchewan')} - option(value='Yukon' selected=province =='Yukon') #{__('Yukon')} - - input#redirect(name='redirect', type='hidden', value='/personal/address') - - +formButtons('Change mailing address', '/personal/address') diff --git a/views/personal/address.pug b/views/personal/address.pug deleted file mode 100755 index dbe33cf..0000000 --- a/views/personal/address.pug +++ /dev/null @@ -1,31 +0,0 @@ -extends ../base - -block variables - -var title = __('Confirm your mailing address') - -block content - - h1 #{title} - - div - p #{__('Please review the address details closely to make sure they’re correct. You can change your address to update our records—this is important for making sure you receive your benefits and tax refund (if applicable).')} - - div - table.pure-table - thead - tr - th #{__('Mailing address')} - tbody - tr - td - .address - if hasData(data, 'personal.address.line2') - div #{data.personal.address.line2}-#{data.personal.address.line1} - else - div #{data.personal.address.line1} - div #{data.personal.address.city}, #{data.personal.address.province} - div #{data.personal.address.postalCode} - - +linkButtons('/financial/income') - a.button-link(href='/personal/address/edit') #{__('Change your mailing address')} - diff --git a/views/personal/maritalStatus-edit.pug b/views/personal/maritalStatus-edit.pug deleted file mode 100755 index 1ea5316..0000000 --- a/views/personal/maritalStatus-edit.pug +++ /dev/null @@ -1,39 +0,0 @@ -extends ../base - -block variables - -var title = __('Change your marital status') - -var maritalStatus = data.personal.maritalStatus - -block content - - h1 #{title} - - div - p #{__('Please choose the correct status from the options listed below.')} - - form.cra-form(method='post') - div(class={['has-error']: errors && errors.maritalStatus}) - fieldset.fieldset - legend.fieldset__legend #{__('Marital Status')} - .multiple-choice.multiple-choice--radios - if errors - +validationMessage(errors.maritalStatus.msg, 'maritalStatus') - .multiple-choice__item - input(id="maritalStatusSingle" name="maritalStatus" type="radio" value="Single" checked=(maritalStatus.toLowerCase()=='single') aria-describedby=(errors ? 'maritalStatus-error' : false)) - label(for="maritalStatusSingle") #{__('Single')} - .multiple-choice__item - input(id="maritalStatusMarried" name="maritalStatus" type="radio" value="Married" checked=(maritalStatus.toLowerCase()=='married' || !data) aria-describedby=(errors ? 'maritalStatus-error' : false)) - label(for="maritalStatusMarried") #{__('Married or common-law')} - .multiple-choice__item - input(id="maritalStatusSeparated" name="maritalStatus" type="radio" value="Separated" checked=(maritalStatus.toLowerCase()=='separated') aria-describedby=(errors ? 'maritalStatus-error' : false)) - label(for="maritalStatusSeparated") #{__('Separated')} - .multiple-choice__item - input(id="maritalStatusDivorced" name="maritalStatus" type="radio" value="Divorced" checked=(maritalStatus.toLowerCase()=='divorced') aria-describedby=(errors ? 'maritalStatus-error' : false)) - label(for="maritalStatusDivorced") #{__('Divorced')} - .multiple-choice__item - input(id="maritalStatusWidowed" name="maritalStatus" type="radio" value="Widowed" checked=(maritalStatus.toLowerCase()=='widowed') aria-describedby=(errors ? 'maritalStatus-error' : false)) - label(for="maritalStatusWidowed") #{__('Widowed')} - - input#redirect(name='redirect', type='hidden', value='/personal/maritalStatus') - - +formButtons('Change Marital Status', '/personal/maritalStatus') diff --git a/views/personal/maritalStatus.pug b/views/personal/maritalStatus.pug deleted file mode 100755 index fe716ca..0000000 --- a/views/personal/maritalStatus.pug +++ /dev/null @@ -1,25 +0,0 @@ -extends ../base - -block variables - -var title = __('Confirm your marital status') - -block content - - h1 #{title} - - div - p #{__('You can find the marital status we have on file below. Click confirm if this is correct or change it. Having your accurate marital status on file is important for you to properly file your taxes and get your benefits.')} - - div - table.pure-table - thead - tr - th #{__('Marital Status')} - tbody - tr - td - div #{__(data.personal.maritalStatus)} - - +linkButtons('/deductions/medical') - a.button-link(href='/personal/maritalStatus/edit') #{__('Change your marital status')} - diff --git a/views/personal/name.pug b/views/personal/name.pug index 20b21ca..4422f7d 100755 --- a/views/personal/name.pug +++ b/views/personal/name.pug @@ -26,6 +26,6 @@ block content form.cra-form(method='post') +yesNoRadios('name', null, 'Is this your name?', errors) - input#redirect(name='redirect', type='hidden', value='/personal/residence') + input#redirect(name='redirect', type='hidden', value='/review') +formButtons() diff --git a/views/personal/residence.pug b/views/personal/residence.pug deleted file mode 100755 index 387d3a8..0000000 --- a/views/personal/residence.pug +++ /dev/null @@ -1,37 +0,0 @@ -extends ../base - -block variables - -var title = __('Confirm your province or territory of residence') - -block content - - h1 #{title} - - div - p #{__('In order to be eligible for this service, your primary residence on December 31, 2018, must have been in Ontario.')} - p #{__('If you live outside of Ontario, we will provide you with alternative options in which you can complete your tax return.')} - - - form.cra-form(method='post') - div(class={['has-error']: errors && errors.residence}) - label(for='residence', name="residence-label") #{__('Province or Territory of Residence')} - if errors - +validationMessage(errors.residence.msg, 'residence') - select#residence(name='residence', autofocus, aria-describedby=(errors && errors.residence ? 'residence-error' : false)) - option(value='Alberta') #{__('Alberta')} - option(value='British Columbia') #{__('British Columbia')} - option(value='Manitoba') #{__('Manitoba')} - option(value='New Brunswick') #{__('New Brunswick')} - option(value='Newfoundland And Labrador') #{__('Newfoundland and Labrador')} - option(value='Northwest Territories') #{__('Northwest Territories')} - option(value='Nova Scotia') #{__('Nova Scotia')} - option(value='Nunavut') #{__('Nunavut')} - option(value='Ontario', selected='selected') #{__('Ontario')} - option(value='Prince Edward Island') #{__('Prince Edward Island')} - option(value='Quebec') #{__('Quebec')} - option(value='Saskatchewan') #{__('Saskatchewan')} - option(value='Yukon') #{__('Yukon')} - option(value='Non Resident') #{__('Non Resident')} - input#redirect(name='redirect', type='hidden', value='/personal/address') - - +formButtons()