This commit is contained in:
Zeeshaun
2026-03-25 11:54:22 -05:00
parent 4d52ebc209
commit 883009770f
776 changed files with 86726 additions and 0 deletions
@@ -0,0 +1,37 @@
# This file doesn't account for some differences:
# 1.VS Code VS Webstorm spaces inside imports. This can be fixed on the Webstorm side with:
# settings -> editor -> code style -> typescript -> spaces -> within -> ES6 import/export braces
# 2. Webstorm places a carriage return on {}, even for simply functions, adjust with:
# settings -> editor -> code style -> typescript -> wrapping and spacing -> simple blocks in one line
# settings -> editor -> code style -> typescript -> wrapping and spacing -> simple methods in one line
# Editor configuration, see http://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
max_line_length = off
trim_trailing_whitespace = false
# EditorConfig is awesome: https://EditorConfig.org
# Matches multiple files with brace expansion notation
# Set default charset
[*.{js,py,ts}]
charset = utf-8
# Indentation override for all JS under lib directory
[lib/**.js]
indent_style = space
indent_size = 2
# Matches the exact files either package.json or .travis.yml
[{package.json,.travis.yml}]
indent_style = space
indent_size = 2
@@ -0,0 +1,412 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Mono auto generated files
mono_crash.*
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# ASP.NET Scaffolding
ScaffoldingReadMe.txt
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Coverlet is a free, cross platform Code Coverage Tool
coverage*.json
coverage*.xml
coverage*.info
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# BeatPulse healthcheck temp database
healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/
# Fody - auto-generated XML schema
FodyWeavers.xsd
=======
# See http://help.github.com/ignore-files/ for more about ignoring files.
# compiled output
/dist
/tmp
/out-tsc
/test-results
/debug.log
# dependencies
/node_modules
# IDEs and editors
/.idea
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
# IDE - VSCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
# misc
/.sass-cache
/connect.lock
/coverage
/libpeerconnection.log
npm-debug.log
yarn-error.log
testem.log
/typings
# System Files
.DS_Store
Thumbs.db
# Patches
*.patch
# the version file shouldn't be saved
src/environments/version.ts
/.vs/slnx.sqlite
/.vs
@@ -0,0 +1,838 @@
# Change Log
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
<a name="4.11.0"></a>
# [4.11.0](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/compare/v4.10.0...v4.11.0) (2021-04-13)
### Bug Fixes
* **CreditApplicationService:** Fix note concatenation ([55dc603](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/55dc603))
### Features
* **HelocRateModPhaseTwo:** Hide additional fields on initial and collateral pages ([424067b](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/424067b))
<a name="4.10.0"></a>
# [4.10.0](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/compare/v4.9.0...v4.10.0) (2021-03-02)
### Bug Fixes
* **HelocRateMod:** Re hide fields that were left behind in change to hidden logic ([c09ec5b](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/c09ec5b))
### Features
* **LoanType:** Add HELOCRateMod Loan Type ([1c264f4](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/1c264f4))
<a name="4.9.0"></a>
## [4.9.0](https://landmarkcu.visualstudio.com///compare/v4.8.0...v4.9.0) (2020-11-16)
### Features
* **employment-info:** Add BSA message to income page ([088c0a2](https://landmarkcu.visualstudio.com///commit/088c0a2831848a17b8b5c4efd0fe1bc9e8df70eb))
### Bug Fixes
* **employment-info:** Move BSA message to translate ([55eb2b1](https://landmarkcu.visualstudio.com///commit/55eb2b14fb49ba98435cafa0f72a2971cddb6ee9))
<a name="4.8.1"></a>
## [4.8.1](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/compare/v4.8.0...v4.8.1) (2020-10-08)
### Enhancements
* **HmdaUI:** Replace DoesNotWishToFurnish option with NotProvided ([914ad21b]((https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/914ad21b)))
* **Hmda:** Update Behaviour for Hmda Form. Only send "NotProvided" if it is the only option selected. (Api)
<a name="4.8.0"></a>
# [4.8.0](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/compare/v4.3.1...v4.8.0) (2020-08-14)
### Features
* **collateralInfoPage:** Add validators to require Wisconsin for HELOC fixed and flex Collaterals ([9719280](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/9719280))
* **equityMemberInfoPage:** Update Equity Member Info Page Getting Started Message For HELOC Fixed a ([0c2ac8e](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/0c2ac8e))
<a name="4.7.0"></a>
# [4.7.0](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/compare/v4.3.1...v4.7.0) (2020-06-19)
### Bug Fixes
* **BranchNameMap:** Pull BranchNameMap from CRIF based on environment ([1373805](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/1373805))
* **Options:** Update Select-Options to include special Loan Types ([248970e](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/248970e))
### Features
* **LoanPurposeOptions:** add 'Refinance Cash-Out' to LoanPurposeOptions for Home Equity and HELOC loans ([adbaaec](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/adbaaec))
<a name="4.6.0"></a>
# [4.6.0](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/compare/v4.3.1...v4.6.0) (2020-06-12)
### Bug Fixes
* **Covid19:** Removed duplicate text from covid loan ([94b5037](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/94b5037))
### Features
* **BranchOptions:** Add 'Brookfield West' 'Greenfield' update 'Brookfield' to 'Brookfield East' ([682564d](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/682564d))
* **Covid19:** Update to the topmost message for covid 19 loans ([723be00](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/723be00))
<a name="4.5.0"></a>
# [4.5.0](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/compare/v4.3.1...v4.5.0) (2020-04-15)
### Bug Fixes
* **SpecialLoan:** Standardize client message field name ([16ea351](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/16ea351))
### Features
* **COVID-19:** Add COVID-19 loan type ([eb466db](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/eb466db))
* **Covid19:** ui updates for covid 19 loan enhancements ([5183fb6](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/5183fb6))
<a name="4.4.0"></a>
# [4.4.0](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/compare/v4.3.1...v4.4.0) (2020-03-31)
### Features
* **COVID-19:** Add COVID-19 loan type ([eb466db](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/eb466db))
<a name="4.3.1"></a>
## [4.3.1](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/compare/v4.3.0...v4.3.1) (2020-03-16)
### Bug Fixes
* **Schumer:** update, start refactor ([45aa896](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/45aa896))
<a name="4.3.0"></a>
# [4.3.0](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/compare/v4.2.1...v4.3.0) (2020-01-10)
### Bug Fixes
* **Test:** Fix broken unit test ([1880541](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/1880541))
### Features
* **Logging:** Log to on-premise seq via proxy ([9b768a5](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/9b768a5))
<a name="4.2.2"></a>
## [4.2.2](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/compare/v4.2.1...v4.2.2) (2019-11-26)
### Features
* **RefiExpress:** Add 8 year term to mortgage refi express loan.
<a name="4.2.1"></a>
## [4.2.1](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/compare/v4.2.0...v4.2.1) (2019-10-25)
### Bug Fixes
* **Environment:** Update prod environment flags ([4a466ab](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/4a466ab))
<a name="4.2.0"></a>
# [4.2.0](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/compare/v3.2.0...v4.2.0) (2019-10-14)
### Bug Fixes
* **CoreTranslate:** Parse core/apex zipcode into zipcode and extension ([915a0cf](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/915a0cf))
* **SchumerBoxes:** Update erroneous schumer box text ([a4f4bc7](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/a4f4bc7))
<a name="3.6.1"></a>
## 3.6.1 (2019-07-12)
### Bug Fixes
* **AddressValidation:** Improve css to support variable screen widths ([23dc937](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/23dc937)), closes [#877](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/877)
* **AddressValidation:** Wrap addrss validation headers ([c6bc17a](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/c6bc17a))
* **Admin:** Fixed unit tests for snackbar ([96f2d68](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/96f2d68)), closes [#871](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/871)
* **AdminExport:** Add member id to admin export ([1fbf058](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/1fbf058)), closes [#1048](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1048)
* **AdminExport:** Add memberid to export ([bf36aad](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/bf36aad))
* **AppResume:** Do not pre-fill member information when resuming a loan ([766bf4b](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/766bf4b)), closes [#1388](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1388)
* **AppStatus:** Add card body to status to support ie11 ([ada0c8a](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/ada0c8a)), closes [#1248](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1248)
* **AppStatus:** Modify the system config page to better reflect the app status ([94634e1](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/94634e1)), closes [#1235](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1235)
* **AppWorkflow:** Allow users to begin existing loans and then switch into a new loan ([cde14b2](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/cde14b2)), closes [#1029](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1029)
* **BranchMapping:** Check for null branch mapping when finding channel Id ([f1fa734](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/f1fa734)), closes [#1053](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1053)
* **CookieTests:** Stop mocking cookies for normal tests. Use spys. ([09e58d5](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/09e58d5)), closes [#1095](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1095)
* **DecisionPage:** Increase the time the application will wait for a decision to 40 seconds. ([02798e0](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/02798e0)), closes [#971](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/971)
* **Employers:** Set all employers as current moving forward ([dd843b8](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/dd843b8)), closes [#1149](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1149)
* **Environment:** Lock test unless users have test role in AD ([8e56bde](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/8e56bde))
* **ErrorDisplay:** Have error display component wait for translations to be ready. ([27941af](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/27941af))
* **ErrorHandling:** Handle errors for member verificaiton and loading existing loans ([b178afb](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/b178afb)), closes [#1044](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1044)
* **ErrorReporting:** USe a simplifier to try and relive the circular object references. ([46355c9](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/46355c9))
* **LoanTranslator:** Use correct ID when translating a loan. ([240055f](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/240055f))
* **LoginFlow:** Add ability to add verification and core loading per environment ([ed1da05](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/ed1da05))
* **MemberLogin:** App startup was attempting to load existing member applications ([b8e1ae5](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/b8e1ae5)), closes [#876](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/876) [#882](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/882)
* **MemberLogin:** Remove return to existing loan link for 3.0 ([63dbb8b](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/63dbb8b))
* **MemberVerification:** Allow member to continue when they can't verify ([c2c7e7e](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/c2c7e7e)), closes [#1393](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1393)
* **MemberVerification:** Dont show the verification page when a user is an authenticated non member ([56f738b](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/56f738b)), closes [#1090](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1090)
* **MockApiModel:** Fix model to correctly populate loan application ([7322112](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/7322112)), closes [#1128](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1128)
* **PersonalInfo:** Reset co-applicant has-same-address flag on co-applicant status change ([22bb115](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/22bb115)), closes [#767](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/767) [#709](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/709)
* **Processing:** Report all processing discrepencies to bugsnag for debugging ([f0e6138](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/f0e6138))
* **ProcessingPage:** Update unit tests, expand wait time ([f9f59fa](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/f9f59fa))
* **SpouseDisclosure:** Show disclosure for coapplicant spouse ([5563bf4](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/5563bf4)), closes [#1050](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1050)
* **Submit:** Use loan id directly from adjusted web service ([0c728c6](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/0c728c6))
* **SummaryComments:** Fix allowance of special characters, prevent bad form submissions ([fe19e39](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/fe19e39)), closes [#1172](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1172)
* **TattleSpouse:** Update tattle spouse copy to be in orange box, move to bottom. ([23e2dcf](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/23e2dcf)), closes [#890](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/890)
* **Tests:** Fix broken unit test ([e8afd47](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/e8afd47))
* **Timeout:** Change timeout info text depending on the preceding page ([c94e68f](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/c94e68f)), closes [#880](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/880)
* **Timeout:** Forward user to landmarkcu.com when timing out completed application ([c924ed5](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/c924ed5)), closes [#967](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/967)
* **TimeOutComponent:** Dont reset credit application when one doesnt exist ([5e59d24](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/5e59d24)), closes [#1176](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1176)
### Features
* **Admin:** Refactor admin to support better error handling ([ce5d790](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/ce5d790)), closes [#871](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/871)
* **Admin:** UI for customer redirect when app is turned off. UI for admins to turn app off. ([870b0c6](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/870b0c6)), closes [#1142](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1142)
* **AdminSystem:** Display server errors in snack bar prompt ([db3ce19](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/db3ce19)), closes [#871](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/871)
* **AppLoader:** Display loan icon next to existing loan list ([3c0c305](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/3c0c305)), closes [#1125](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1125)
* **AppStatus:** Added a new decision status for tracking in admin ([efbb683](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/efbb683)), closes [#1133](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1133)
* **BoatTerms:** Update minimum term length for boats to 63 months ([d3cfcec](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/d3cfcec)), closes [#883](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/883)
* **CookieDisclosure:** Additional text for cookie disclosure ([bd4f297](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/bd4f297)), closes [#963](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/963)
* **CoreAccess:** Change to all cookie based security, no direct ID manipulation ([607487c](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/607487c))
* **CoreAccess:** Prefill member info, get individual id ([091adae](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/091adae)), closes [#799](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/799)
* **CoreIntegration:** Replace mock services with real restful calls ([c40d42e](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/c40d42e)), closes [#1162](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1162)
* **EmploymentStatus:** Removed retired status from dropdown ([62f3159](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/62f3159)), closes [#1180](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1180)
* **ErrorHandling:** Report errors to logging service instead of bugsnag ([785400c](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/785400c)), closes [#1179](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1179)
* **MemberLogin:** Catch login status and throw appropriate error messages ([d002541](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/d002541)), closes [#1129](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1129)
* **MemberLogin:** Disable member login for 3.0 release ([758ca0b](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/758ca0b)), closes [#931](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/931)
* **MemberLogin:** Route user to lmcu login when they click the existing app link ([6b28315](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/6b28315)), closes [#1037](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1037)
* **MemberVerification:** Front end implementation of core work. Includes verification & continue of ([fc57b12](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/fc57b12)), closes [#766](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/766)
* **Options:** Added test coverage to option classes ([636eb8b](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/636eb8b)), closes [#1218](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1218)
* **Prefill:** Prefill member primary address ([7f2c57d](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/7f2c57d))
* **ReviewWording:** Allow review wording to be based on loan type ([ff2fb4a](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/ff2fb4a))
* **StatusToolTip:** Added tooltip to status column in admin page ([62058dd](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/62058dd)), closes [#1163](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1163)
<a name="4.1.0"></a>
# [4.1.0](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/compare/v3.2.0...v4.1.0) (2019-09-04)
### Bug Fixes
* **CoreTranslate:** Parse core/apex zipcode into zipcode and extension ([915a0cf](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/915a0cf))
<a name="4.0.0"></a>
# [4.0.0](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/compare/v3.2.0...v4.0.0) (2019-07-26)
### Features
* **AppWorkflow:** Allow users to begin existing loans and then switch into a new loan ([cde14b2](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/cde14b2)), closes [#1029](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1029)
* **LoanTranslator:** Use correct ID when translating a loan. ([240055f](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/240055f))
* **LoginFlow:** Add ability to add verification and core loading per environment ([ed1da05](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/ed1da05))
* **MemberLogin:** App startup was attempting to load existing member applications ([b8e1ae5](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/b8e1ae5)), closes [#876](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/876) [#882](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/882)
* **MemberLogin:** Remove return to existing loan link for 3.0 ([63dbb8b](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/63dbb8b))
* **MemberVerification:** Allow member to continue when they can't verify ([c2c7e7e](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/c2c7e7e)), closes [#1393](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1393)
* **MemberVerification:** Dont show the verification page when a user is an authenticated non member ([56f738b](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/56f738b)), closes [#1090](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1090)
* **Admin:** Refactor admin to support better error handling ([ce5d790](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/ce5d790)), closes [#871](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/871)
* **Admin:** UI for customer redirect when app is turned off. UI for admins to turn app off. ([870b0c6](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/870b0c6)), closes [#1142](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1142)
* **AdminSystem:** Display server errors in snack bar prompt ([db3ce19](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/db3ce19)), closes [#871](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/871)
* **AppLoader:** Display loan icon next to existing loan list ([3c0c305](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/3c0c305)), closes [#1125](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1125)
* **AppStatus:** Added a new decision status for tracking in admin ([efbb683](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/efbb683)), closes [#1133](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1133)
* **BoatTerms:** Update minimum term length for boats to 63 months ([d3cfcec](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/d3cfcec)), closes [#883](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/883)
* **CookieDisclosure:** Additional text for cookie disclosure ([bd4f297](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/bd4f297)), closes [#963](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/963)
* **CoreAccess:** Change to all cookie based security, no direct ID manipulation ([607487c](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/607487c))
* **CoreAccess:** Prefill member info, get individual id ([091adae](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/091adae)), closes [#799](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/799)
* **CoreIntegration:** Replace mock services with real restful calls ([c40d42e](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/c40d42e)), closes [#1162](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1162)
* **EmploymentStatus:** Removed retired status from dropdown ([62f3159](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/62f3159)), closes [#1180](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1180)
* **ErrorHandling:** Report errors to logging service instead of bugsnag ([785400c](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/785400c)), closes [#1179](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1179)
* **MemberLogin:** Route user to lmcu login when they click the existing app link ([6b28315](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/6b28315)), closes [#1037](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1037)
* **MemberVerification:** Front end implementation of core work. Includes verification & continue of ([fc57b12](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/fc57b12)), closes [#766](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/766)
* **Options:** Added test coverage to option classes ([636eb8b](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/636eb8b)), closes [#1218](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1218)
* **Prefill:** Prefill member primary address ([7f2c57d](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/7f2c57d))
* **ReviewWording:** Allow review wording to be based on loan type ([ff2fb4a](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/ff2fb4a))
* **StatusToolTip:** Added tooltip to status column in admin page ([62058dd](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/62058dd)), closes [#1163](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1163)
<a name="3.6.1"></a>
# [3.6.1](2019-07-12)
### Other
* **Processing:** Display different messages for for credit cards.
* **SchumerBoxes:** Update text of schumer boxes
<a name="3.6.0"></a>
# [3.6.0](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/compare/v3.5.1...v3.6.0) (2019-04-29)
### Bug Fixes
* **Admin:** Fixed unit tests for snackbar ([96f2d68](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/96f2d68)), closes [#871](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/871)
* **Employers:** Set all employers as current moving forward ([dd843b8](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/dd843b8)), closes [#1149](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1149)
* **Environment:** Lock test unless users have test role in AD ([8e56bde](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/8e56bde)), no ticket
* **ErrorHandling:** Handle errors for member verification and loading existing loans ([b178afb](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/b178afb)), closes [#1044](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1044)
* **MemberVerification:** Dont show the verification page when a user is an authenticated non member ([56f738b](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/56f738b)), closes [#1090](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1090)
* **Submit:** Use loan id directly from adjusted web service ([0c728c6](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/0c728c6)), no ticket
* **SummaryComments:** Fix allowance of special characters, prevent bad form submissions ([fe19e39](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/fe19e39)), closes [#1172](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1172)
* **TimeOutComponent:** Dont reset credit application when one doesnt exist ([5e59d24](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/5e59d24)), closes [#1176](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1176)
* **USPS:** Better handle USPS errors when users enter nonsense addresses, closes 1157
### Features
* **Admin:** Refactor admin to support better error handling ([ce5d790](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/ce5d790)), closes [#871](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/871)
* **Admin:** UI for customer redirect when app is turned off. UI for admins to turn app off. ([870b0c6](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/870b0c6)), closes [#1142](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1142)
* **AdminSystem:** Display server errors in snack bar prompt ([db3ce19](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/db3ce19)), closes [#871](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/871)
* **AppLoader:** Display loan icon next to existing loan list ([3c0c305](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/3c0c305)), closes [#1125](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1125)
* **AppStatus:** Added a new decision status for tracking in admin ([efbb683](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/efbb683)), closes [#1133](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1133)
* **EmploymentStatus:** Removed retired status from dropdown ([62f3159](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/62f3159)), closes [#1180](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1180)
* **MemberLogin:** Catch login status and throw appropriate error messages ([d002541](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/d002541)), closes [#1129](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1129)
* **MemberLogin:** Route user to lmcu login when they click the existing app link ([6b28315](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/6b28315)), closes [#1037](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1037)
* **Options:** Added test coverage to option classes ([636eb8b](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/636eb8b)), closes [#1218](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1218)
* **StatusToolTip:** Added tooltip to status column in admin page ([62058dd](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/62058dd)), closes [#1163](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1163)
* **ApiRoot:** Further change API root to redirect to client, fixing both Azure and lost consumers, closes #1156
### Other
* **MemberLogin:** Disable member login, pre-fill and other 4.0 code.
<a name="3.5.0-Release"></a>
# [3.5.0-Release](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/compare/v3.2.0...v3.5.0-Release) (2019-04-10)
### Bug Fixes
* **AdminExport:** Add memberid to export ([bf36aad](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/bf36aad))
### Features
* **MemberVerification:** Front end implementation of core work. Includes verification & continue of ([fc57b12](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/fc57b12)), closes [#766](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/766)
<a name="3.5.1"></a>
# [3.5.1](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/compare/v3.5.0...v3.5.1) (2019-04-15)
### Bug Fixes
* **LoanAdmin:** All users to submit loans marked VENDOR_ERROR to CRIF, closes #1131
<a name="3.5.0"></a>
# [3.5.0](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/compare/v3.2.0...v3.5.0) (2019-04-10)
### Bug Fixes
* **AddressValidation:** Wrap addrss validation headers ([c6bc17a](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/c6bc17a)), closes #1067
* **AdminExport:** Add member id to admin export ([1fbf058](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/1fbf058)), closes [#1048](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1048)
* **BranchMapping:** Check for null branch mapping when finding channel Id ([f1fa734](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/f1fa734)), closes [#1053](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1053)
* **PersonalInfo:** Reset co-applicant has-same-address flag on co-applicant status change ([22bb115](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/22bb115)), closes [#767](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/767) [#709](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/709), #993
* **SpouseDisclosure:** Show disclosure for coapplicant spouse ([5563bf4](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/5563bf4)), closes [#1050](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1050)
* **TattleSpouse:** Update tattle spouse copy to be in orange box, move to bottom. ([23e2dcf](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/23e2dcf)), closes [#890](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/890)
### Features
* **LoanStorage:** Cache mongo client instance, add more tests., closes #767, #993
* **Azure:** move the api status call to root so azure sees it, closes #752
<a name="3.4.0"></a>
# [3.4.0](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/compare/v3.2.0...v3.4.0) (2019-04-03)
### Bug Fixes
* **ProcessingPage:** Update unit tests, expand wait time ([f9f59fa](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/f9f59fa))
* **Timeout:** Forward user to landmarkcu.com when timing out completed application ([c924ed5](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/c924ed5)), closes [#967](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/967)
* **BranchMapping:** Handle double submission errors in IE 11, closes #992
* **CRIF:** Handle Error 13 as a 'try again' error, closes #710
### Features
* **CookieDisclosure:** Additional text for cookie disclosure ([bd4f297](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/bd4f297)), closes [#963](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/963)
* **ApiStatus:** Report API status as root route for Azure, closes #752
* **MongoDB:** Cache Cosmos/Mongo connection for improved performance
<a name="3.3.2"></a>
# [3.3.2](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/compare/v3.2.0...v3.4.0) (2019-03-28)
### Bug Fixes
* **Processing:** Report all processing discrepencies to bugsnag for debugging ([f0e6138](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/f0e6138))
<a name="3.3.1"></a>
# [3.3.1](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/compare/v3.2.0...v3.4.0) (2019-03-27)
### Bug Fixes
* **DecisionPage:** Increase the time the application will wait for a decision to 40 seconds. ([02798e0](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/02798e0)), closes [#971](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/971)
<a name="3.3.0"></a>
# [3.3.0](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/compare/v3.2.0...v3.3.0) (2019-03-21)
### Bug Fixes
* **MemberLogin:** Remove return to existing loan link for 3.0 ([63dbb8b](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/63dbb8b))
* **TattleSpouse:** Update tattle spouse copy to be in orange box, move to bottom. ([23e2dcf](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/23e2dcf)), closes [#890](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/890)
### Features
* **MemberLogin:** Disable member login for 3.0 release ([758ca0b](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/758ca0b)), closes [#931](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/931)
* **BoatTerms:** Update minimum term length for boats to 63 months ([d3cfcec](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/d3cfcec)), closes [#883](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/883)
<a name="3.2.1"></a>
## [3.2.1](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/compare/v3.2.0...v3.2.1) (2019-03-20)
### Bug Fixes
* **AddressValidation:** Improve css to support variable screen widths ([23dc937](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/23dc937)), closes [#877](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/877)
* **MemberLogin:** App startup was attempting to load existing member applications ([b8e1ae5](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/b8e1ae5)), closes [#876](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/876) [#882](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/882)
* **Timeout:** Change timeout info text depending on the preceding page ([c94e68f](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/c94e68f)), closes [#880](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/880)
<a name="3.2.0"></a>
# [3.2.0](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/compare/v3.0.0...v3.2.0) (2019-03-20)
### Bug Fixes
* **BranchConfig:** Last updated date was not shown on branch admin screen. ([17298e1](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/17298e1)), closes [#833](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/833)
* **BranchExport:** Remove quotes from branch export, add more testing. ([e74d8af](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/e74d8af)), closes [#872](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/872)
* **LoanAPI:** Remove forced exception test, allowing loans to complete. closes #873, backend.
* **MemberLogin:** App startup was attempting to load existing member, closes #883, addresses #876
### Features
* **Admin:** Add error with start date and end date format ([1a25207](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/1a25207)), closes [#878](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/878)
* **TattleSpouse:** Add additional tattle spouse text inside orange box ([8010fb8](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/8010fb8)), closes [#874](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/874)
<a name="3.1.0"></a>
# [3.1.0](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/compare/v3.0.0...v3.1.0) (2019-03-19)
### Bug Fixes
* **BranchConfig:** Last updated date was not shown on branch admin screen. ([17298e1](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/17298e1)), closes [#833](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/833)
<a name="3.0.0"></a>
# [3.0.0](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/compare/v1.10.0...v3.0.0) (2019-03-18)
### Bug Fixes
* **Admin:** Save filter settings between pages ([ad8efc5](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/ad8efc5)), closes[#1412]
* **Admin:** Sort fields as case insensitive ([72ac98e](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/72ac98e)), closes[#1411]
* **AdminDropDownLists:** Fixed lists in IE ([dde4448](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/dde4448)), closes[#1396]
* **Alimony:** Pass alimony information correctly to wizard service, fix tests. ([8721e6c](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/8721e6c)), no ticket
* **AppLoader:** Fix crash on loading of empty list of existing loans ([a170c65](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/170c65)), no ticket
* **AppRouting:** Use ternary operators instead of functions for canactivate ([ec5852c](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/ec5852c)), closes[#1465]
* **BranchMapping:** Map 53037 to westbend branch ([e3de1fe](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/e3de1fe)), closes[#1407]
* **CoApplicantSpouse:** Fixes a broken unit test ([ca68c74](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/ca68c74)), no ticket
* **CollateralInfoPage:** Patch occupancy type using enum instead of string ([c2fe840](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/c2fe840)), closes[#1196]
* **DisclosureDate:** Dont initialize valuealize value ([fb5a9f6](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/fb5a9f6)), closes[#1406]
* **Security:** Send withcredentials in more requests ([10c5674](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/10c5674)), no ticket
* **HeaderStatus:** Remove loantype from header when navigating back to select loan page ([de709e7](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/de709e7)), closes[#1362]
* **LandingPage:** Changed language on vehicle selection and headers ([8a2bacd](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/8a2bacd)), closes[#1363]
* **NameSuffix:** Deleted an important line of code in the last merge ([060021f](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/060021f)), no ticket
* **PersonalInfo:** Add correct icons to Middle initial and suffix display ([b496880](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/b496880)), closes[#1341]
* **Processing:** Rewriting processing page to avoid out of order errors ([be1bf7f](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/be1bf7f)), closes [#1365](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1365)
* **ProcessingPage:** Capital S on last line of status ([a7087af](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/a7087af)), closes[#1340]
* **RouteGuards:** Activate route guards ([59e9416](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/59e9416)), closes[1332]
* **SchumerBoxes:** Update Schumer Box rates for reward, student and cash back ([d9fc111](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/d9fc111)), no ticket
* **Security:** Only all users with admin role to see admin screen, test role for qa access. ([183073b](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/183073b)), closes [#1329](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1329)
* **Security:** Request from microsoft graph if specific user is in admin group ([260922a](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/260922a)), closes [#1329](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1329)
* **Summary:** Format Other Income amount as dollars ([9190f6c](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/9190f6c)), closes [#1335](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1335)
* **SummaryCollateral:** Fix collateral typo ([e508cb4](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/e508cb4)), closes[#1187]
* **SummaryPageButton:** Change disabled color to grey ([c5e4e4f](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/c5e4e4f)), closes[#1388]
* **UrlParsing:** Strip off extra characters when parsing urls ([1c057bd](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/1c057bd)), closes [#1323](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1323)
* **VehicleTranslator:** Use credit app purpose of loan for boats, rvs, powersports ([d4f12f7](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/d4f12f7)), closes[#1401]
* **AmountValidation:** Added amount validation on monthly payment and vehicle collateral ([739f0eb](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/739f0eb)), closes #1342
### Features
* **AddressValidation:** Increased header line height to support all browsers ([4e48711](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/4e48711)), closes #1370
* **AddressVerification:** Move button location for better ux ([2c7adba](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/2c7adba)), closes #1370
* **Admin:** New admin landing page for choosing features ([4e27e73](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/4e27e73)), closes #1065
* **AdminExport:** Updated csv export with additional fields ([19899c8](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/19899c8)), closes #1419
* **AdminHome:** Added home navigation for admin pages ([15fa86b](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/15fa86b)), closes #1449
* **AdminPage:** Allow user input of date field ([eb79236](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/eb79236)), closes #1416
* **AdminSystem:** Export table into csv ([fc75b4e](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/fc75b4e)), closes #1231
* **AdminSystem:** Save vendor loan id as part of the json model. Display in admin system. ([eb5d0d2](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/eb5d0d2)), closes #1170
* **AdminSystem:** Tooltip for search field ([022d998](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/022d998)), closes #1414
* **AdminTimeout:** Redirect users to admin home when timed out ([16d7418](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/16d7418)), closes #1418
* **API:** Update api urls to custom domain names ([3a53dc6](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/3a53dc6)), closes [#1402](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1402) [#1378](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1378)
* **AppNote:** Capture datetime of when user completes disclosure page ([10cddd7](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/10cddd7)), closes #1406
* **BranchMapping:** Allow download and upload of branch mappings with error checking ([d5581db](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/d5581db)), closes [#1443](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1443)
* **CookieDisclosure:** Added cookie disclosure to first page of application ([a2aac4d](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/a2aac4d)), closes #1404
* **CopyRightYear:** Use year function to get current year for copyright ([39872c2](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/39872c2)), closes #1346
* **Disclosure:** Change text of disclosure box ([594e307](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/594e307)), closes #1417
* **e2eTests:** Added e2e test coverage to new landing pages ([4c29727](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/4c29727)), no ticket.
* **Income:** Allow multiple other and employer incomes. ([dc7947d](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/dc7947d)), closes [#565](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/565), closes #1181
* **LoanTerms:** Updated vehicle loan terms ([84b3776](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/84b3776)), closes #1397
* **MemberLogin:** Cookie auth, saml end point, UX for members ([609bc7e](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/609bc7e)), closes #1379
* **MultipleEmployers:** Added ability to add up to three employment incomes ([4be1d4b](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/4be1d4b)), closes [#1181](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1181)
* **NameHeaders:** Format applicant name as title case when shown back to the user ([5491f19](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/5491f19)), closes #1427
* **Notes:** Force user to select primary contact method ([27934e6](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/27934e6)), closes #1305
* **PageTitles:** Change page titles to sentence style ([b1326ea](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/b1326ea)), closes #1428
* **PartialAppLoader:** Allows saved applications to be loaded and continued seemlessly ([39f446d](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/39f446d)), closes [#1198](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1198)
* **PromoCode:** Add promo code field to the summary page ([a9caadf](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/a9caadf)), closes #1334
* **SalaryAmount:** Changed minimum salary amount to 0 dollars ([cfed9d2](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/cfed9d2)), closes #1343
* **SaveAndContinue:** Adjusts API calls to match new save => update => submit flow ([20098a7](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/20098a7)), closes [#1368](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1368)
* **Security:** Limit access to admin pages to specific AD group, limit DEV/QA to both groups. ([e981887](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/e981887)), closes #1325
* **SuffixSelect:** Add choose one select to suffix select ([dc05c6a](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/dc05c6a)), closes #1422, #1341
* **TimeoutPage:** Timeout page will now route back to admin if user was at admin ([796e48e](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/796e48e)), closes #1451
* **Translator:** Append timestamp to en.json file to prevent caching ([daeb36e](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/daeb36e)), closes #1424
* **Translator:** Convert error messages to translator. ([922a64c](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/922a64c)), closes #1290
* **VisaTrademark:** Added registered trademark to visa text ([e57bd91](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/e57bd91)), closes #1389
### Performance Improvements
* **AdminModule:** Create unique admin module for the admin system ([a261206](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/a261206)), no ticket
* **MemberComponent:** Added unit tests to the member components and services ([d1bd1f9](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/d1bd1f9)), no ticket
### Reverts
* **CosmosIdInSession:** Roll back previous changes ([8862ca0](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/8862ca0)), closes [#1372](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1372)
<a name="2.1.1"></a>
# [2.1.1](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/compare/v1.10.0...v2.1.2) (2019-02-13)
### Bug Fixes
* **PersonalInfoForm:** Add default value to suffix ([06d8cf7](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/06d8cf7)), closes [#1422](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1422)
* **Admin:** Update list of zip codes and branch mappings
<a name="2.1.0"></a>
# [2.1.0](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/compare/v1.10.0...v2.1.0) (2019-02-11)
### Bug Fixes
* **SchumerBoxes:** Update Schumer Box rates for reward, student and cash back ([d9fc111](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/d9fc111))
### Features
* **Environment:** Up API urls in environment files to new domain names ([6385803](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/6385803)), closes [#1402](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1402)
<a name="2.0.0"></a>
# [2.0.0](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/compare/v1.10.0...v2.0.0) (2019-01-11)
### Bug Fixes
* **CollateralPage:** Adds a max value validator to the "Estimated Value" field ([e32ae31](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/e32ae31)), closes [#1173](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1173)
### Features
* **LoanTerms:** Updated 2019 loan terms for vehicles ([87a7a50](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/87a7a50))
<a name="1.9.0"></a>
# [1.9.0](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/compare/v1.8.2...v1.9.0) (2019-01-07)
### Bug Fixes
* **AddressValidationView:** updates the UX for Address Validation piece ([edc581a](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/edc581a)), closes [#1242](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1242)
* **LoanPurpose:** Correct display the default loan purpose selection for heloc loans ([e94a646](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/e94a646)), closes [#1324](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1324)
* **MemberInfoComponent:** Display error message with matching field label ([c87c1c8](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/c87c1c8))
* **NumbersWithDecimals:** Numbers with decimals not 'unmasked' correctly ([ed163c6](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/ed163c6)), closes [#1240](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1240)
### Features
* **AuthenticationGuard:** Configures The Auth guard to authenticate non-prod environments ([d4e0705](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/d4e0705)), closes [#1217](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1217)
* **CurrencyFormatter:** Eliminate decimals when not needed ([41bee05](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/41bee05))
* **EmploymentInfoPage:** Defaults the number of months employed to "0" ([c422bd4](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/c422bd4)), closes [#1195](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1195)
* **PersonalInfo:** New suffix field on personal info pages ([d8e6c96](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/d8e6c96))
<a name="1.8.2"></a>
## [1.8.2](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/compare/v1.8.1...v1.8.2) (2018-12-12)
### Bug Fixes
* **LienPayoffFont:** Updates the font for "Payoff" prompt on CollateralPage. ([7c2a27b8])
(https://landmarkcu.visualstudio.com/_git/LoanWizard/commit/7c2a27b8d4c2bb28460682092da3e2532475f003), closes [#1194]
<a name="1.8.1"></a>
## [1.8.1](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/compare/v1.8.0...v1.8.1) (2018-12-10)
### Bug Fixes
* **VehicleValutation:** Changes the messaging for vehicle valuation. ([826dcca1]), closes [#1227]
<a name="1.8.0"></a>
# [1.8.0](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/compare/v1.7.0...v1.8.0) (2018-12-04)
### Bug Fixes
* **Headers:** Remove feature header, causing browser problems. ([b97c278](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/b97c278))
* **SummaryPage:** Full info spouse sections of the summary page did not have a title ("Your spouse's ([5ef5e58](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/5ef5e58)), closes [#1205](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1205)
* **SaveOnlyValidIndividuals:** The backend will validate Individual's and reject the save if they d ([af01465](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/af01465)), closes [#1202](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1202)
* **CORS:** Move CORS from Azure to Code, no ticket.
### Features
* **ShowSavingProgress:** Upon saving, the UI will disable the "NEXT" button and add a 'inprogress' ([8484bda](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/8484bda)), closes [#1199](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1199)
<a name="1.7.0"></a>
# [1.7.0](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/compare/v1.4.0...v1.7.0) (2018-12-03)
### Bug Fixes
* **AddressValidation:** Hides the compare address view when address group is invalid ([16fbb07](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/16fbb07)), closes [#1165](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1165)
* **EquityTranslator:** Allow null values in equity/vehicle translator ([b4c44db](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/b4c44db)), no ticket.
* **FontAndAddress:** Fixed a font class. Fixed 'saving' real estate verified address ([7d16084](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/7d16084)), closes [#1194](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1194)
* **Header:** Don't link header to main site, update vehicle loan type header ([d3379fd](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/d3379fd)), closes [#1131](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1131) [#1132](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1132)
* **I18N:** Fix error messages to allow custom error messages ([c6f73ad](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/c6f73ad)), closes #1149
* **LoanTermYearCalc:** Grab present year loan terms for future years ([0155a93](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/0155a93)), closes #1096
* **PenTest:** Update web.config with security headers, remove location.href reference. ([2fd35c9](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/2fd35c9)), closes #1176, #1177
* **ProcessingPage:** Changed the bugsnag error on decision page timeout to a notification in bugsnag ([d6457d8](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/d6457d8)), closes [#1150](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1150)
* **Spouses:** 2 fixes, spouse info needs to disappear when we change to co-applicant spouse, 'same r ([9f7cf7d](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/9f7cf7d)), closes [#1141](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1141)
* **VehicleSummaryTemplate:** hide vehicle condition for the vehicle types that dont ask for conditio ([1f7b495](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/1f7b495)), closes [#1155](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1155), #1172
* **Waypoints:** fix mobile way point messaging ([7505116](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/7505116)), closes [#1127](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1127)
* **Branch-Zip:** Update zip/branch mapping, closes #1174
### Features
* **AddressValidation:** Adds address validation functionality, injects it to all address input form ([a605680](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/a605680)), closes [#1178](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1178) [#1180](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1180) [#1168](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1168)
* **AddressValidation:** Adds address validation story to UI ([8f743b2](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/8f743b2)), closes [#84](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/84)
* **AdminPage:** A new admin page was created for landmark employees to review loans ([0f0e4ea](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/0f0e4ea)), closes #17
* **bugsnag:** add error to bugsnag for decisioning ([da3a3df](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/da3a3df)), no ticket
* **CommonGroups:** Only alpha characters in the name fields ([1a90415](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/1a90415)), closes [#1110](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1110)
* **employment-income:** limits on hourly and annual income ([4165165](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/4165165)), closes #1160
* **environment:** use before send hook to stop bug snag reports ([d362192](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/d362192)), no ticket
* **LienPosition:** Added lien position functionality to the front end ([e309377](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/e309377)), closes [#1026](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1026), #1025
* **LienPositionManufacturedHome:** Added logic on front end for lien position for manufactured home ([3886202](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/3886202)), closes [#1153](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1153)
* **LoanSubmission:** Save progress of loan applications. Submit via cosmos db ([b81fda2](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/b81fda2)), closes #17
* **LoanTerms:** Signature and preapproval support up to and year truncation ([cec6f5b](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/cec6f5b))
* **LoanTerms:** Up to appended on shortest loan term ([7e71e66](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/7e71e66))
* **MemberComponentVehicleComponent:** Dropdowns disabled when no valid options exist, updated e2e t ([183b841](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/183b841)), closes [#1125](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1125)
* **MetaData:** Add loan meta data into loan container ([4fbe780](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/4fbe780)), closes #1170
* **PersonalInfoForms:** Add custom message for alpha only name fields ([78486ae](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/78486ae)), closes [#1110](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1110)
* **robots:** disable bots from crawling site ([c16fdb0](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/c16fdb0)), closes #1152
* **SECURITY:** Upgrade IIS headers in web.config per pentest ([8912a59](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/8912a59)), closes #1176, #1177
* **Translate:** Allow over-riding individual error messages, pull messages from Translate file ([000e025](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/000e025)), closes [#1149](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1149)
* **vehicle-collateral:** Vehicle Seller Conditional Show Hide ([ba00d24](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/ba00d24)), closes #1082
* **KeyVault:** Update API to use Azure Key Vault to read API keys and other secrets, closes #1041
### Performance Improvements
* **bugsnag:** move bug snag api key ([ce0bb7b](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/ce0bb7b)), closes #1041
<a name="1.6.1"></a>
# 1.6.1(2018-11-12)
### Bug Fixes
* **SchumerBoxes:** Update Schumer Box rates for reward, student and cash back
<a name="1.6.0"></a>
# [1.6.0](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/compare/v1.4.0...v1.6.0) (2018-11-12)
### Bug Fixes
* **LoanTermYearCalc:** Grab present year loan terms for future years ([0155a93](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/0155a93)), closes #1147
### Features
* **Translate:** Allow over-riding individual error messages, pull messages from Translate file ([000e025](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/000e025)), closes [#1149](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1149)
* **CRIF:** Equity Loan without HMDA information for non-signing spouse (co-applicant to CRIF), closes #1140
<a name="1.5.0"></a>
# [1.5.0](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/compare/v1.4.0...v1.5.0) (2018-11-08)
### Bug Fixes
* **Header:** Don't link header to main site, update vehicle loan type header ([d3379fd](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/d3379fd)), closes [#1131](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1131) [#1132](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1132)
* **Spouses:** Spouse removed when changed to co-applicant spouse ([9f7cf7d](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/9f7cf7d)), closes [#1141](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1141)
* **Spouses:** Residence is same was not properly required ([9f7cf7d](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/9f7cf7d)), closes [#1141](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1141)
* **Waypoints:** fix mobile way point messaging ([7505116](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/7505116)), closes [#1127](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1127)
* **TermValidator:** Support the entire range of vehicle years (0 - 9999) without failing, closes #1135
* **PowersportLoanTermValidator:** Use estimated amount for loanterm calculations on powersports, closes #1136
* **UX:** Show inverted correct and error field icons (x/checkmark), closes #1103
### Features
* **CommonGroups:** Only alpha characters in the name fields ([1a90415](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/1a90415)), closes [#1110](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1110)
* **LoanTerms:** Signature and preapproval support up to and year truncation ([cec6f5b](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/cec6f5b)), closes #1098
* **LoanTerms:** Up to appended on shortest loan term ([7e71e66](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/7e71e66)), closes #1098
* **PersonalInfoForms:** Add custom message for alpha only name fields ([78486ae](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/78486ae)), closes [#1110](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1110)
* **vehicle-collateral:** Vehicle Seller Conditional Show Hide ([3e1820a](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/3e1820a)), closes #1082
<a name="1.4.0"></a>
# [1.4.0](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/compare/v1.3.0...v1.4.0) (2018-11-07) [Patch]
### Bug Fixes
* **Header:** Fix bug where mobile header displays [object object] instead of loan type, closes #1127
* **CRIF:** Update vehicle seller wording in app note, closes #1128
* **Setting:** Update minimum amount for boat and manufactured terms in loan term settings, closes #1130
<a name="1.4.0"></a>
# [1.4.0](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/compare/v1.3.0...v1.4.0) (2018-11-06)
### Bug Fixes
* **ApiTranslator:** Apply TCPA disclosure individually ([b9da0ec](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/b9da0ec)), closes [#1092](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1092)
* **ApiTranslator:** Unmask the other income and child support consistently with income ([da22a7e](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/da22a7e)), closes [#1080](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1080)
* **Build:** Fix the build based on injecting a non DI service ([32af4e6](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/32af4e6))
* **SpouseInfoSaving:** Spouse Information was getting overwritten by a 'save' call in AWService ([a59d69e](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/a59d69e)), closes [#1102](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1102), #1124
* **SpouseTypes:** When spouse-related input changes, some previously entered info should be nullifie ([b0a6f8e](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/b0a6f8e)), closes [#1090](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1090) [#1124](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1124)
* **VehicleCollateralTerms:** When 'termOptions' change in local state we must ensure that the value ([b9f2eba](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/b9f2eba)), closes [#1096](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1096), closed #1096, #1097
### Features
* **Email_format:** NG's default email validator did not match the regex pattern that CRIF requires ([447438e](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/447438e)), closes [#1115](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1115)
* **HMDA_Gender:** Gender doesn't have to be Male or Female, it can be both ([fd4d7a7](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/fd4d7a7)), closes [#1116](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1116)
* **VehicleTerms:** Vehicle terms were refactored and updated accross all vehicle types ([7c2770d](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/7c2770d)), closes #1096, #1097
* **CRIF** Vehicle seller added as an additional application note, closes #1082
* **CRIF** Uppercase user entered fields, closes #1087
* **CRIF** Send all dates in correct time zone, closes #1109
<a name="1.3.0"></a>
# [1.3.0](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/compare/v1.2.0...v1.3.0) (2018-11-02)
### Bug Fixes
* **PowerSports:** Update powersports labels, also display correct vehicle type on summary screen. ([80907fc](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/80907fc)), Closes #1099
* **residencesummary:** Adjust previous address heading on summary page ([3bb0c52](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/3bb0c52)), closes [#1107](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1107)
* **SpouseButtons:** Format spouse buttons to match other buttons ([bade806](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/bade806)), closes [#1104](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1104)
* **spouselabel:** Uppercase all spouse labels used on buttons for page navigation ([b5b3ea9](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/b5b3ea9)), closes [bug#1106](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1106)
* **VehicleCollateral:** "Term of Loan" was not patching correctly. ([1de237d](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/1de237d)), closes [#1117](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1117)
* **VehicleCollateral:** "Term of Loan" was not patching correctly. ([115e508](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/115e508)), closes [#1117](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1117)
### Features
* **Labels:** Support showing separate labels for loan type in header and copy ([1f6c279](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/1f6c279)), closes #1100
* **SummaryPage:** Add loan term to summary page ([2778fdd](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/2778fdd)), closes [#1101](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1101)
<a name="1.2.0"></a>
# [1.2.0](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/compare/v1.0.10...v1.2.0) (2018-10-30)
### Bug Fixes
* **ConfigurationService:** Change the service to not load from the server more than once. ([66645db](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/66645db))
* **decisionpage:** fix loan terms for powersports ([7541bce](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/7541bce))
* **decisionpage:** use config service for url instead of hardcoded ([aea7278](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/aea7278))
* **MonthsResidedEmployed:** Fix the maximum months resided and employed to be < 131 per crif max ([1adb412](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/1adb412))
* **vehiclecollateral:** refactor vc component ([e06d3b8](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/e06d3b8))
* **Labels:** Fix two appliant -> applicant labels.
### Features
* **CRIF** Send HMDA loan flag
<a name="1.1.0"></a>
# [1.1.0](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/compare/v1.0.10...v1.1.0) (2018-10-29)
### Bug Fixes
* **collateralinfo:** use msrp for term length ([1962cda](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/1962cda))
* **Labels:** Update all powersports labels to read Personal Water Craft ([aab02cc](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/aab02cc))
* **vehiclecollateral:** use msrp for loan terms ([914f36b](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/914f36b))
* **TCPA:** Opt-out now sent to CRIF correctly
### Features
* **DisclosureInfo:** Fixes a compile error ([72fd9db](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/72fd9db)), closes [#1085](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1085)
* **ApiTranslator:** Adds disclosure information to loan application submission ([3d6103a](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/3d6103a)), closes [#1085](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1085)
<a name="1.0.10"></a>
## 1.0.10 (2018-10-26)
### Bug Fixes
* **Powersports** Fix the power sports label to be Personal Water Craft / Jet Ski.
* **LoanTypes** Fixes Signature loan apicode and adds unique api translator for headers.
* **DecisionPage** allow all servers besides production to display the loan id. (QA)
* **ApiTranslator** Properly translate secondary phone #.
* **ApiTranslator** Include middle name for tattle spouse.
* **ApiTranslator** Fix HMDA notice disclosed field.
* **CRIF** Fix HMDA determination fields, gender, ethnicity, race, fix not-applicable value.
### Features
* **CRIF** Alimony/Child support are no longer INCOME
* **LoanLimits** Adjust vehicle loan limits to 250 from 5000
<a name="1.0.8"></a>
## 1.0.8 (2018-10-24)
### Bug Fixes
* **ApiTranslator:** Correctly send the hmdaNoticeDisclosed field to the server. ([014c185](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/014c185)), closes [#1069](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/issues/1069)
* **Api:** Correctly format the hmda fields for do not disclose situations.
<a name="1.0.7"></a>
## [1.0.7](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/compare/v1.0.6...v1.0.7) (2018-10-22)
<a name="1.0.6"></a>
## [1.0.6](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/compare/d314e83...v1.0.6) (2018-10-22)
### Bug Fixes
* **project:** Add commit validation using husky and enable conventional changelog ([334bd20](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/334bd20))
### Features
* Install and create basic setup for Commitizen ([d314e83](https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/commits/d314e83))
@@ -0,0 +1,33 @@
# docker build -t ola-ui .
# docker run --rm -p 8080:80 --name ola-ui ola-ui
FROM node:14-bullseye AS build
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --unsafe-perm --before=2025-09-01 --ignore-scripts
# Copy the source code.
COPY . .
# Run scripts skipped during npm ci (generates src/environments/version.ts).
RUN npm run postinstall
# Build the production bundle. Using npx avoids platform-specific npm script wrappers.
# Note: base-href/deploy-url set for hosting under /loanapp.
RUN npx ng build \
--base-href="/loanapp/" \
--deploy-url="/loanapp/"
FROM nginx:1.25-alpine AS runtime
COPY docker/nginx.conf /tmp/default.conf
RUN rm -f /etc/nginx/conf.d/default.conf && \
mv /tmp/default.conf /etc/nginx/conf.d/default.conf
COPY --from=build /app/dist/ui /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
@@ -0,0 +1,372 @@
# Introduction
TODO: Give a short introduction of your project. Let this section explain the objectives or the motivation behind this project.
# Getting Started
TODO: Guide users through getting your code up and running on their own system. In this section you can talk about:
1. Installation process
2. Software dependencies
3. Latest releases
4. API references
# Build and Test
TODO: Describe and show how to build your code and run the tests.
# Contribute
TODO: Explain how other users and developers can contribute to make your code better.
If you want to learn more about creating good readme files then refer the following [guidelines](https://docs.microsoft.com/en-us/azure/devops/repos/git/create-a-readme?view=azure-devops). You can also seek inspiration from the below readme files:
- [ASP.NET Core](https://github.com/aspnet/Home)
- [Visual Studio Code](https://github.com/Microsoft/vscode)
- [Chakra Core](https://github.com/Microsoft/ChakraCore)
=======
# Landmark Credit Union Loan Application
This readme outlines the developer process, basic coding style guide and provides guidance and details around the technical approach to the user interface. You should always review and update this document to encompass your changes.
# Known Contacts
The known contacts for this application are Jeff Knaub and Jerry Wenzen.
# Getting Started
Before you can work with the code, build it, or deploy it you will need a proper developmenet environment. The required environment is basically Git, Node, and something to work with C#.
This environment code has been wrapped up into a Powershell script that should run on any Windows 10 machine and produce a viable development environment to carry you through this guide.
The script is available in the root of this directory as `setup-env.ps1`.
You should start by reviewing and possibly running that script if needed.
## Testing Notes on LandmarkCu.com / online banking
The application is now integrated with Online Banking. Testing this is more difficult and involves having online banking
pointed at the dev application. The process flow is documented in the architecture documents, but also briefly included
here.
1. User logs into online banking
2. User clicks the apply for loan button
3. Online banking POSTs a SAML token to the api end point.
4. If valid a redirect to the application is returned, and cookies will be attached.
Cookies are required, and test online banking accounts are required. Additionally, there is a pipe from Azure to
on-premise so that we can call the core for member information.
## Working With The Code
Code is checked out from the Azure DevOps Repository, which is currently [https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard] with the back end code
located at [https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizardAPI].
Work should be done in a branch from Develop. In the shared folder there is a software development process document that talks about this, you should start there. A brief introduction will be included here.
Start by checking out the repository, and specifically the develop branch. You should be branching off of develop
with your own working branch. When you are complete, you will create a pull request within VSTS here: [https://landmarkcu.visualstudio.com/LoanWizard/_git/LoanWizard/pullrequests]
Before submitting your pull request, review the following:
* Did you commit with commitizen? `git cz` (see below)
* Did you add all needed unit testing, and ensure all existing tests are passing?
* Have you run the e2e tests and ensured they all pass?
In order to work and submit code, the project will need to be built and run. Instructions follow. Generally the project doesn't need to be built, just run locally. However, running a production build after major changes will ensure the production build is still working before CI runs.
### Build
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build.
You can also use npm to run these commands:
Run `npm run build` to build the project with default settings.
Run `npm run build-nvisia` to build the project with default settings.
Run `npm run build-release` to build the project with release settings (configuration for qa).
Run `npm run build-prod` to build the project with production settings (and build optimizer).
### Run (Development server)
Run `npm run start` for a dev server. Navigate to `https://localhost:4200/`. The app will automatically reload if you change any of the source files.
Note that this will run with a proxy in place so that you can contact the web services.
This start script is in the package.json file, and runs `ng serve --proxy-config proxy.conf.json --configuration=local --ssl`
### Run (Develop, QA, Prod)
Deployments to Develop, QQ, and Prod are automatically handled by Azure Dev-Ops. See the additional resources section below; as there is a document outlining the software development process, as well as the cloud setup Azure.
### Running unit tests
Run `npm run test` to run the unit tests with code coverage.
Run `npm run test-debug` to run the unit tests without code coverage, but with full stack traces.
Run `npm run test-interactive` if you want to use real chrome for debugging and not headless.
Firefox, IE, and Edge are also supported in this project. Run the ng test command and pass in the desired browser(s) into the browser argument
Example: ng test --watch=false --browsers Firefox,Chrome,IE,Edge --no-progress
### Running end-to-end tests
Tests run against Chrome and Firefox in parallel.
Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
Run `npm run update-e2e` if someone has changed the protractor config and you are getting errors; this usually fixes the problem. You may also need
to run this if you are missing one of the browsers in the configuration.
### Resources
There is additional documentation available within the Landmark shared folders; you should look for the following files, or ask someone for them if you can't find them. Start in the "Phase 1 Final Documents" folder under the 'LCU Credit App 2018' folder:
* LCU Credit App 2018: This is a folder
* The following documents, plus additional documents should be available in this folder, get access to it as soon as possible.
* Architecture Document: Landmark Credit Union - Credit Application - SAD
* This is the software architecture description.
* Site Layout / Reference: Landmark_Site_Reference.XLSX
* This shows urls/locations for source code and deployables and the Azure configuration
* Software Process: landmark_software_process.docx
* Outlines the process for working with the source code.
* Azure Key Vault keys
* Outlines each key used by the API and it's purpose
* Additional notes on OLA's coding and components can also be found in the repo's wiki
* https://landmarkcu.visualstudio.com/LoanWizard/_wiki/wikis/Loan%20Wizard%20Wiki/
### Suggestion for IDE
* Visual Studio Code
* Webstorm
# Architecture
The best explanation for the architecture can be found by referencing the document listed in the resources section above. However if you are looking to do
something specific, here are some tips.
A. Add a new loan type
0. If you are adding a sub-type to an existing type, you do not need to follow all of these steps, these instructions cover adding a new category of loan type.
0. See: loan-type.ts, credit-card-outline.ts, credit-card-routing.module.ts, application-wizard.service.ts, credit-application.service.ts, credit-application-dao.service.ts, api-translator.service.ts
1. Begin in loan-type.ts file; add your type.
2. Create an Outline, start by looking at credit-card-outline.ts.
3. With your outline created, create a set of routes similar to credit-card-routing.module.ts
4. Add any needed sets of fields to common-groups.ts
5. Create a new pages in the loan-wizard/wizards folder.
6. Create any new field groups needed in the loan-wizard/field-groups folder.
7. If you need custom waypoints, that is in loan-wizard/controls folder.
8. update the CreditApplicationService to support any new fields.
9. update the ApplicationWizardService to support any new fields and pages.
10. Update the api-translator for any fields that need to be submitted to the back end, this is in shared/api-translator.
11. Add your loan to app/select-loan if needed.
12. Make sure to add additional unit testing as needed for all new code.
99. Don't forget you may need to change the back end services!
B. Change an environment
1. There is currently local, prod, e2e, and default. These are in src/environments, but you must also change angular.json!!!!!
C. Add e2e testing
1. This is under the e2e folder.
2. There is a folder for each major loan type, and a shared folder for common pages.
3. Add your folder and tests per the existing pattern, adding to shared when possible.
4. In the protractor.conf.js file is where we specify which test files are run, and on which browsers.
5. Don't forget to update your protractor install, there is a script in the package.json "npm run update-e2e"
D. Something not listed here
1. The file structure for this project is organized as a hybrid - most code is organized by feature, with shared code organized under
the shared folder. If you are looking for something with common behavior, start in app/shared. Otherwise it's best to start in app/loan-wizard.
2. It's fairly easy to find the code for a specific page - use the route shown in your browser, like this:
> https://applydev.azurewebsites.net/loan-wizard/cc/st/step-2
The 'CC' part is the category, and the 'ST' is the type. The 'step-2' is the page.
1. Check the various routing modules to find your category (cc is credit card), this is *-routing.module.ts
2. Find the route in that module corresponding to the page (step-2 in this case), the component listed is the code for
that page. Start there. In this case, CC leads to credit-card-routing.module.ts which leads to the PersonalInfoPageComponent.
3. Beyond this, you should refer to the architectural document and spend some time reviewing the code.
# Releases
Releases are handled by anyone on the team with access to VSTS. Generally when a pull request is accepted
to develop, that will be automatically built and deployed to DEV. The Dev application is here: [https://applydev.landmarkcu.com]. The
same is true for the back end / API. When you want to make a release, you must revise the changelog (CHANGELOG.md file). This
is a two step process:
1. run 'npm run release' in the develop branch, this will:
A. Update the version in package.json automatically.
B. Update the CHANGELOG.md file automatically
2. Update/Review the CHANGELOG.md as needed, usually for:
A. Add backend features/fixes/etc
B. Add missing ticket numbers (or 'no ticket')
C. Remove duplicates
You can force a version number if needed by changing the package.json, package-log.json, and CHANGELOG.md. Once you are
done revising you can 'git commit --amend --no-edit' and then 'git push -f' will push the release to develop.
To get to QA, develop must be merged into the release branch and pushed. This will automatically cause the release
branch to be build and the resulting release to be pushed to QA.
To get to production, release must be merged into master and pushed. This will automatically cause the
code to be built and packaged as artifacts. However the release process is manual, and can be done
here: [https://landmarkcu.visualstudio.com/LoanWizard/_release]
When creating releases, it's important not to forget to make a release and update the change notes as
needed. There is information on creating a release below. An important tip is that on the website
you can hover over the landmark copyright in the bottom left to see the released client version.
## Setup Commitizen and Produce changelogs and release notes
Commitizen is a command line tool that helps format commit messages with a series of prompts that are used to
generate a commit message. We use this tool to standardize our commits for tracking a changelog and producing release
notes.
* `npm install commitizen -g`
* `npm install commitizen --save-dev` // Already done for you, skip.
* `npm install cz-conventional-changelog --save-dev` // Already done for you, skip.
* `npm install --save-dev validate-commit-msg` // Already done for you, skip.
* `npm install -g conventional-changelog-cli`
Instead of committing with `git commit` commit with `git cz`
This will force your messages into the format <type>(<scope>): <subject>
Definition | Description
-----------|------------
feat | A new feature
fix | A bug fix
docs | Documentation only changes
style | Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
refactor | A code change that neither fixes a bug nor adds a feature
perf | A code change that improves performance
test | Adding missing or correcting existing tests
chore | Changes to the build process or auxiliary tools and libraries such as documentation generation
Here is how semantic-release will map these to release types and how it maps to [semantic verioning](https://semver.org/#summary):
Commit message | Release type
----------------|--------------
`fix(pencil): stop graphite breaking `<br>`when too much pressure applied` | Patch Release (PATCH)
`feat(pencil): add 'graphiteWidth' option` | Feature Release (MINOR)
`BREAKING CHANGE: The graphiteWidth option `<br>`has been removed. The default graphite`<br>` width of 10mm is always used for performance reasons.` | Breaking Release (MAJOR)
## Produce or update the changelog
You shouldn't need to do this, it should be generated for you when you create a release (below)
* Create changelog from scratch: `conventional-changelog -p angular -i CHANGELOG.md -s -r 0`
* Update the changelog: `conventional-changelog -p angular -i CHANGELOG.md -s `
## Produce a release
* Use: `npm run release`
Resources:
* http://www.nullfactory.net/2017/04/enforce-commit-message-standards-and-generate-changelogs-via-git/
* https://dev.bleacherreport.com/how-we-use-commitizen-to-clean-up-commit-messages-a16790dcd2fd
* http://devboosts.com/2017/03/28/conventional-commits/
* https://medium.com/@LeonardoBrAu/why-git-squash-and-rebase-commits-and-how-we-do-it-87aa17406e21
# ADA Compliance
This application is targeting level AA ADA Compliance, here is the checklist you should keep in mind when developing:
* Every image, video file, audio file, plug-in, etc. has an alt tag
* Complex graphics are accompanied by detailed text descriptions
* The alt descriptions describe the purpose of the objects
* If an image is also used as a link, the alt tag describes the graphics and the link destination
* Decorative graphics with no other function have empty alt descriptions (alt=””)
* Data tables have the column and row headers appropriately identified (using the tag)
* Make sure the page does not contain repeatedly flashing images
* Check to make sure the page does not contain a strobe effect
* All scripts and plug-ins and the content within them are accessible to assistive technologies, or else an alternative means of accessing equivalent content is provided
* When form controls are text input fields use the LABEL element
* When text is not available use the title attribute
* Include any special instructions within field labels
* Make sure that form fields are in a logical tab order
* Include a ‘Skip Navigation’ button to help those using text readers
* SVG icons should not focusable by tabbing in IE (utilize `focusable="false"` on all icon tags)
## Coding tools for ADA Compliance
* Refer to here for help: https://getbootstrap.com/docs/4.0/getting-started/accessibility/
* Refer to here for practical examples: http://www.punkchip.com/aria-basic-findings/
* use aria-label, aria-expanded, and aria-hidden as needed.
* Bootstrap: sr-only, bootstrap provides sr-only so that you can show things to people with screen readers. (sr-only stands for screen readers only)
# Style Concerns
1) Make sure the validators listed are full and correct.
2) Make sure the error display component shows all validators you are using.
3) Make sure default value is provided at the model level.
4) A field cannot be a number, be part of a select, and have blank ('') as the default. Make these non-numbers if possible.
5) Select boxes should all start on their default, which should derive from the MODEL.
6) Select boxes title/default should be "Please Choose" if they do not have a default value.
7) Select boxes and text inputs should have class="form-control".
8) every <form> declaration should have an `(ngSubmit)="commandNext()"`.
9) Next button should be at the LEFT, the back button should be BEFORE it.
10) Next button should say "Continue", not "Next".
* Always keep the web development checklist in mind: http://webdevchecklist.com/
* `(click)` bindings should bind to a CommandXXX function with Command as a prefix. This denotes to anyone looking at the component that a given function is
UX driven.
* Keep minimal functionality in Components, they should act as minimal controllers. Refactor work and business logic to a service.
* You should have unit tests for all components and services.
* Take your time with naming and ask the team for help; but take naming seriously so that your components and services are recognizable.
* Review the .editorconfig file if you are notices style differences in PRs, resolve any problems with the team.
* DO NOT use angular material for the loan application system! Angular material should only be used for the admin system.
# Libraries
* https://github.com/ngx-translate/core
## Admin System Dependencies
* @angular/cdk
* @angular/material
## Angular Material
* Angular material is a library used exclusively for the admin system.
* Provides the datatable with native sorting/paging/filtering
## Angular
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 6.0.8 with the command `ng new ui --routing --style scss`
The project's package.json has been updated with various libraries and scripts; it should always be reviewed.
## Code scaffolding
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
We do not generally use the code scaffolding.
# FAQ
Q. I'm running the unit test and I see output like this:
`HeadlessChrome 68.0.3440 (Windows 10.0.0) XYZComponent should use the service to add address controls to the form group FAILED
[object ErrorEvent] thrown
`
A. Re-run the tests using `npm run test-debug`, which will show the full stack trace but not provide code coverage.
Q. What do I need to know about NGX-Translate
A. The primary translation file is en.json, and is loaded asynchronously (it could be moved out of project); this is setup in the app.module.ts by
using a TranslateHttpLoader. Some entries have HTML, if you want to use HTML in an entry, you have to bind to [innerHtml]
Html example: `<h6 translate [innerHTML]="'COPY.DISCLOSURES' | translate: localState"></h6>`
non-html example `<h6 translate>{{'COPY.DISCLOSURES' | translate: localState}}</h6>`
You should refer to the ngx-translate documentation for full usage and instructions.
Q. What do I need to know about Security?
A. There are many security concerns outlines in the architecture documents in the share (see resources above). To add to it, there are multiple security mechanisms at play. One is for Landmark employees, and uses the ADAL-Angular-6 library to authenticate against Azure AD. The other is with NCR/DI and is used to authenticate members; this is handld in the API and the client uses this via checking for cookies. Be careful not to mix up these two methods.
# File Upload Component and Azure Blob Storage
The file upload component allows users and dealerships to upload files to ACTion. This is handled with both Azure Blob Storage and CosmosDB. CosmosDB has a list of files associated with a loan application that contains information about the file and the GUID of the file in Blob Storage.
When an application is submitted or a dealership clicks transmit, the LoanApplicationController will get the CosmosDB record for the list of files and loop over them to transmit them to ACTion. After the files have been transmitted to ACTion, they are removed from Blob Storage.
The files that aren't ever transmitted to ACTion will remain in Blob Storage (this can happen from API failure or if a dealership closes the form without transmitting). Files that are older than 30 days will be removed automatically by a rule set in the Lifecycle section of Azure.
# Dealership Portal
The dealership portal can be accessed via ```/dealership-portal``` and allows dealerships to upload documents to an ACTion loan. There are four required fields that are used to authenticate a dealership: dealership code, dealership password, application ID, and the primary applicant's last name/full business name.
## Dealership Code
```(string, case-sensitive, max length: 60)```
2-3 digit code that is automatically generated by ACTion when a dealership is added. It takes the first letter of the dealership's name and then increments the number based on other dealerships with the same first letter. So if there were 9 dealerships that started with B (```B1-B9```), the next B-named dealership would become ```B10```.
It also appears that it converts dealerships that begin with a number to the first letter of that number, e.g. ```5``` -> ```F```; so ```5 Corners Dodge``` becomes ```F6```, as it is the 6th dealership to begin with ```F```.
The dealership code can be found within ACTion.
## Dealership Password
```(string, case-sensitive, max-length 30)```
This password is not a password in the traditional sense, as it is being stored in the plain-text field ```costCenterCode``` within ACTion. Dealership's will not have access to create/change their password, so it must be done by someone at Landmark with access to ACTion.
## Application ID
```(integer)```
Self-explanatory
## Primary Applicant's Last Name or Business Full Name
```(string, case-insensitive, max-length: 250)```
When the authentication request is made, the application is taken from ACTion, the ```primaryBorrower``` field is inspected for ```idRef``` which contains the GUID of the primary borrower. The primary borrower can be an individual or a company. Once this ID is found, the API loops over the individuals and companies associated with the application until it finds the matching ID.
Once the matching ID is found, it will return the ```lastName``` if it is an individual or the ```tradeName``` if it is a company. The request much match this value exactly, but is not case-sensitive.
## Other notes
This portal utilizes the file upload component, which is the same component used for the loan application process. Any changes to this component that is specific to the dealership portal must be made with caution as those changes will affect all loan processes that use it.
In non-production environments, you can force an error to happen to test what happens if a file transmission error occurs by uploading the first file with the name ```do-not-allow-transmission.jpg```. The API will see this file and return a ```500```.
@@ -0,0 +1 @@
cinst -y kind
@@ -0,0 +1,7 @@
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
extraPortMappings:
- containerPort: 30000
hostPort: 80
@@ -0,0 +1,17 @@
kind create cluster --config kind.cluster.config --wait 300s
kubectl create namespace landmarkcu
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
helm install my-release ingress-nginx/ingress-nginx `
--set controller.service.type=LoadBalancer `
--set controller.service.nodePorts.http=30000 `
--set controller.service.nodePorts.https=30001
docker build -t local/online-loan-app:1.0 ..
kind load docker-image local/online-loan-app:1.0
kubectl apply -k ..\_deploy\overlays\local
@@ -0,0 +1 @@
kind delete cluster
@@ -0,0 +1,174 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"ui": {
"root": "",
"sourceRoot": "src",
"projectType": "application",
"prefix": "app",
"schematics": {
"@schematics/angular:component": {
"styleext": "scss"
}
},
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist/ui",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "src/tsconfig.app.json",
"assets": [
"src/favicon.ico",
"src/assets",
"src/web.config",
"src/Robots.txt"
],
"styles": [
"src/styles.scss"
],
"scripts": [
"./node_modules/@fortawesome/fontawesome/index.js",
"./node_modules/@fortawesome/fontawesome-free-solid/index.js",
"./node_modules/@fortawesome/fontawesome-free-regular/index.js"
],
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"extractCss": true,
"namedChunks": false,
"aot": true,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true
},
"configurations": {
"production": {},
"local": {
"optimization": false,
"outputHashing": "none",
"sourceMap": true,
"extractCss": false,
"namedChunks": true,
"aot": false,
"extractLicenses": false,
"vendorChunk": true,
"buildOptimizer": false
},
"dev": {
"optimization": false,
"outputHashing": "none",
"sourceMap": true,
"extractCss": false,
"namedChunks": true,
"aot": false,
"extractLicenses": false,
"vendorChunk": true,
"buildOptimizer": false
},
"e2e": {
"optimization": false,
"outputHashing": "none",
"sourceMap": true,
"extractCss": false,
"namedChunks": true,
"aot": false,
"extractLicenses": false,
"vendorChunk": true,
"buildOptimizer": false
},
"qa": {},
"uat": {}
}
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "ui:build"
},
"configurations": {
"production": {
"browserTarget": "ui:build:production"
},
"local": {
"browserTarget": "ui:build:local"
},
"uat": {
"browserTarget": "ui:build:uat"
},
"e2e": {
"browserTarget": "ui:build:e2e"
}
}
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "ui:build"
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "src/test.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "src/tsconfig.spec.json",
"karmaConfig": "src/karma.conf.js",
"styles": [
"src/styles.scss"
],
"scripts": [],
"assets": [
"src/favicon.ico",
"src/assets"
]
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"src/tsconfig.app.json",
"src/tsconfig.spec.json"
],
"exclude": [
"**/node_modules/**"
]
}
}
}
},
"ui-e2e": {
"root": "e2e/",
"projectType": "application",
"architect": {
"e2e": {
"builder": "@angular-devkit/build-angular:protractor",
"options": {
"protractorConfig": "e2e/protractor.conf.js",
"devServerTarget": "ui:serve:e2e"
},
"configurations": {
"production": {
"devServerTarget": "ui:serve:production"
}
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": "e2e/tsconfig.e2e.json",
"exclude": [
"**/node_modules/**"
]
}
}
}
}
},
"defaultProject": "ui"
}
@@ -0,0 +1,53 @@
parameters:
- name: target_environment
displayName: Target Environment
type: string
default: qa
values:
- qa
- uat
- prd
- name: k8s_namespace
displayName: K8s Namespace to deploy to
type: string
default: landmarkcu
values:
- landmarkcu
variables:
- template: ./config-files/${{ parameters.target_environment }}-pvars.yaml
- name: source_branch_name
value: $[replace(replace(variables['Build.SourceBranch'], 'refs/heads/', ''), '/', '-')]
- name: docker_container_repository_name
value: landmarkcu/lcu.api.internal.onlineloanapp
resources:
repositories:
- repository: azdo_pipeline_templates
type: git
name: Infrastructure Platform/azdo-pipeline-templates
ref: main
stages:
# DOCKER BUILD AND PUSH
- template: docker-build-push.yaml@azdo_pipeline_templates
parameters:
azdo_agent_pool: $(pvar_azdo_agent_pool)
docker_registry_service_connection: $(pvar_docker_registry_service_connection)
docker_container_repository_name: $(docker_container_repository_name)
dockerfile_path: ./Dockerfile
docker_image_tags: |
build-$(Build.BuildId)
$(source_branch_name)
# K8S DEPLOY
- template: k8s-deploy.yaml@azdo_pipeline_templates
parameters:
dependsOn: CI
condition: or(eq(variables['Build.SourceBranchName'], 'develop'), eq(variables['Build.SourceBranchName'], 'main'))
azdo_agent_pool: $(pvar_azdo_agent_pool)
kubectl_version: $(pvar_kubectl_version)
k8s_service_connection: $(pvar_k8s_service_connection)
k8s_namespace: ${{ parameters.k8s_namespace }}
k8s_kustomization_path: ./kustomize/overlays/${{ parameters.target_environment }}
docker_registry_service_connection: $(pvar_docker_registry_service_connection)
docker_image_to_deploy: $(docker_container_repository_name):build-$(Build.BuildId)
@@ -0,0 +1,10 @@
trigger:
branches:
include:
- '*'
exclude:
- 'main'
- 'develop'
extends:
template: azure-k8s-pipeline.yaml
@@ -0,0 +1,10 @@
trigger:
branches:
include:
- 'main'
extends:
template: azure-k8s-pipeline.yaml
parameters:
target_environment: prd
k8s_namespace: landmarkcu
@@ -0,0 +1,10 @@
trigger:
branches:
include:
- 'develop'
extends:
template: azure-k8s-pipeline.yaml
parameters:
target_environment: qa
k8s_namespace: landmarkcu
@@ -0,0 +1,10 @@
trigger:
branches:
include:
- 'main'
extends:
template: azure-k8s-pipeline.yaml
parameters:
target_environment: uat
k8s_namespace: landmarkcu
@@ -0,0 +1,7 @@
---
variables:
pvar_azdo_agent_pool: vmss-sub-df-lcu-apps-prd-lz-uscz
pvar_docker_registry_service_connection: Docker Registry LMCU
pvar_k8s_service_connection: svcon-sub-df-lcu-apps-prd-aks-k8s-uscz
pvar_kubectl_version: 1.25.9
pvar_azdo_agent_pool_nuget: LCUOnPrem
@@ -0,0 +1,7 @@
---
variables:
pvar_azdo_agent_pool: vmss-sub-df-lcu-apps-qa-lz-uscz
pvar_docker_registry_service_connection: Docker Registry LMCU
pvar_k8s_service_connection: svcon-sub-df-lcu-apps-qa-aks-k8s-uscz
pvar_kubectl_version: 1.25.9
pvar_azdo_agent_pool_nuget: LCUOnPrem
@@ -0,0 +1,7 @@
---
variables:
pvar_azdo_agent_pool: vmss-sub-df-lcu-apps-uat-lz-uscz
pvar_docker_registry_service_connection: Docker Registry LMCU
pvar_k8s_service_connection: svcon-sub-df-lcu-apps-uat-aks-k8s-uscz
pvar_kubectl_version: 1.25.9
pvar_azdo_agent_pool_nuget: LCUOnPrem
@@ -0,0 +1,24 @@
server {
listen 80;
server_name _;
root /usr/share/nginx/html;
index index.html;
# Serve the app under /loanapp, stripping the prefix for static assets and
# falling back to the SPA entrypoint for deep links.
location /loanapp/ {
rewrite ^/loanapp/(.*)$ /$1 break;
try_files $uri $uri/ /index.html;
}
# Fallback for any other paths (e.g., health checks).
location / {
try_files $uri $uri/ /index.html;
}
# Basic security headers.
add_header X-Content-Type-Options "nosniff";
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
}
@@ -0,0 +1,35 @@
// Protractor configuration file, see link for more information
// https://github.com/angular/protractor/blob/master/lib/config.ts
const { SpecReporter } = require('jasmine-spec-reporter');
exports.config = {
allScriptsTimeout: 11000,
specs: [
'./src/credit-card/*.e2e-spec.ts',
'./src/select-loan/*.e2e-spec.ts',
'./src/heloc/*.e2e-spec.ts',
'./src/vehicle/*.e2e-spec.ts',
'./src/signature/*.e2e-spec.ts'
],
multiCapabilities: [{
'browserName': 'chrome'
}, {
'browserName': 'firefox'
}],
directConnect: true,
baseUrl: 'http://localhost:4200/',
framework: 'jasmine',
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 30000,
print: function() {}
},
onPrepare() {
require('ts-node').register({
project: require('path').join(__dirname, './tsconfig.e2e.json')
});
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
// Do not do this! browser.waitForAngularEnabled(false);
}
};
@@ -0,0 +1,153 @@
import { browser, by, element, ElementFinder, protractor } from 'protractor';
import { CreditCardPageOnePo } from './pages/page-one.po';
import { ContactPagePo } from '../shared/pages/contact-page.po';
import { PageObjectTools } from '../shared/page-object-tools';
import { ResidencePagePo } from '../shared/pages/residence-page.po';
import { EmploymentPagePo } from '../shared/pages/employment-page.po';
import { CreditCardDisclosuresPagePo } from './pages/page-disclosures.po';
import { SummaryPagePo } from '../shared/pages/summary-page.po';
import { SpouseTypePagePo } from '../shared/pages/spouse-type-page.po';
describe('It should create a credit card application for 4 full info individuals', () => {
it('should accept maximum inputs for page 1 (Member/Loan Type)', () => {
const page = new CreditCardPageOnePo();
browser.get(page.PAGE_URL);
browser.sleep(1000);
expect(page.getFocusedElement()).toEqual(page.getFirstElement());
let inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMaximum();
inputArray = PageObjectTools.findFieldsInPageByIdArray([...page.ALL_FIELDS, ...page.HIDDEN_FIELDS_1]);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length + page.HIDDEN_FIELDS_1.length);
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept minimum inputs for page 2.A (Personal Info)', () => {
const page = new ContactPagePo();
expect(page.getFocusedElement()).toEqual(page.getFirstElement());
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsPrimaryMarriedButNotMarriedToCoApplicant();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept minimum inputs for page 3.A (Residence)', () => {
const page = new ResidencePagePo();
expect(page.getFocusedElement()).toEqual(page.getFirstElement(page.DEFAULT_PREFIX));
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMinimalLivingInWI();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept minimum inputs for page 4.A (Employment)', () => {
const page = new EmploymentPagePo();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept FULL INFO SPOUSE input for Applicant spouse type page', () => {
const page = new SpouseTypePagePo();
expect(page.canGoNext()).toEqual(false);
page.fillFieldsFullInfoSpouse();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept minimum inputs for page 2.B (Applicant\'s Spouse Personal Info)', () => {
const page = new ContactPagePo();
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMinimalNoMarital();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept minimum inputs for page 3.B (Applicant\'s Spouse Residence)', () => {
const page = new ResidencePagePo();
page.markAddressSame();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept minimum inputs for page 4.B (Applicant\'s Spouse Employment)', () => {
const page = new EmploymentPagePo();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept maximum inputs for page 2.C (Co-Applicant Personal Info)', () => {
const page = new ContactPagePo();
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMaximumCoApplicantNonPrimary();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept minimum inputs for page 3.C (Co-applicant Residence)', () => {
const page = new ResidencePagePo();
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMinimalLivingInWI();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept minimum inputs for page 4.C (Co-applicant Employment)', () => {
const page = new EmploymentPagePo();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept FULL INFO SPOUSE input for CoApplicant spouse type page', () => {
const page = new SpouseTypePagePo();
expect(page.canGoNext()).toEqual(false);
page.fillFieldsFullInfoSpouse();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept minimum inputs for page 2.D (CoApplicant\'s Spouse Personal Info)', () => {
const page = new ContactPagePo();
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMinimalNoMarital();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept minimum inputs for page 3.D (CoApplicant\'s Spouse Residence)', () => {
const page = new ResidencePagePo();
page.markAddressSame();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept minimum inputs for page 4.D (CoApplicant\'s Spouse Employment)', () => {
const page = new EmploymentPagePo();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should maximum inputs for page 5 (Disclosures)', () => {
const page = new CreditCardDisclosuresPagePo();
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMinimal();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should show application information on page 6 (Summary)', () => {
const page = new SummaryPagePo();
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
page.fillFieldsMinimal();
expect(page.canGoNext()).toEqual(true);
});
});
@@ -0,0 +1,129 @@
import { browser, by, element, ElementFinder, protractor } from 'protractor';
import { CreditCardPageOnePo } from './pages/page-one.po';
import { ContactPagePo } from '../shared/pages/contact-page.po';
import { PageObjectTools } from '../shared/page-object-tools';
import { ResidencePagePo } from '../shared/pages/residence-page.po';
import { EmploymentPagePo } from '../shared/pages/employment-page.po';
import { CreditCardDisclosuresPagePo } from './pages/page-disclosures.po';
import { SummaryPagePo } from '../shared/pages/summary-page.po';
import { WizardPagePo } from '../shared/pages/wizard-page.po';
describe('It should allow free navigation of a completed credit card application', () => {
it('should accept maximum inputs for page 1.', () => {
const page = new CreditCardPageOnePo();
browser.get(page.PAGE_URL);
page.fillFieldsMaximum();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept maximum inputs for page 2 (Personal Info)', () => {
const page = new ContactPagePo();
page.fillFieldsMaximumCoApplicant();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept maximum inputs for page 3 (Residence)', () => {
const page = new ResidencePagePo();
page.fillFieldsMinimal();
page.showMailingAddress();
page.showSecondAddress();
page.fillAdditionalFieldsMaximum();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept maximum inputs for page 4 (Employment)', () => {
const page = new EmploymentPagePo();
page.showEmploymentFields();
page.showOtherIncomeFields();
page.showChildSupportFields();
page.fillFieldsMaximum();
expect(page.canGoNext()).toEqual(false);
page.fillChildSupportFields();
page.fillOtherIncomeFields();
page.markSingleIncomeNotEnough();
expect(page.canGoNext()).toEqual(true);
// Will no longer happen.
// page.fillSecondIncome();
// expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept maximum inputs for page 2.A (Co-Applicant Personal Info)', () => {
const page = new ContactPagePo();
page.fillFieldsMaximum();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept maximum inputs for page 3.A (Co-applicant Residence)', () => {
const page = new ResidencePagePo();
page.markAddressNotSame();
expect(page.getFocusedElement()).toEqual(page.getFirstElement(page.DEFAULT_PREFIX));
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMinimal();
page.showMailingAddress();
page.showSecondAddress();
page.fillAdditionalFieldsMaximum();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept maximum inputs for page 4.A (Co-applicant Employment)', () => {
const page = new EmploymentPagePo();
let inputArray = PageObjectTools.findFieldsInPageByIdArray(page.STARTING_FIELDS);
expect(inputArray.length).toEqual(page.STARTING_FIELDS.length);
expect(page.canGoNext()).toEqual(true);
page.showEmploymentFields();
inputArray = PageObjectTools.findFieldsInPageByIdArray([...page.EMPLOYMENT_FIELDS], page.DEFAULT_PREFIX);
expect(inputArray.length).toEqual([...page.EMPLOYMENT_FIELDS].length);
expect(page.canGoNext()).toEqual(false);
page.showOtherIncomeFields();
page.showChildSupportFields();
page.fillFieldsMaximum();
expect(page.canGoNext()).toEqual(false);
page.fillChildSupportFields();
page.fillOtherIncomeFields();
page.markSingleIncomeNotEnough();
// Will no longer happen.
// expect(page.canGoNext()).toEqual(false);
// page.fillSecondIncome();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should maximum inputs for page 5 (Disclosures)', () => {
const page = new CreditCardDisclosuresPagePo();
page.fillFieldsMinimal();
expect(page.canGoNext()).toEqual(true);
});
it('should jump back to the beginning.', () => {
const urlList = [
'http://localhost:4200/loan-wizard/cc/cb/co-applicant-financial',
'http://localhost:4200/loan-wizard/cc/cb/co-applicant-residential',
'http://localhost:4200/loan-wizard/cc/cb/co-applicant-personal',
'http://localhost:4200/loan-wizard/cc/cb/step-4',
'http://localhost:4200/loan-wizard/cc/cb/step-3',
'http://localhost:4200/loan-wizard/cc/cb/step-2',
'http://localhost:4200/loan-wizard/cc/cb/step-1'
];
const page = new WizardPagePo();
urlList.forEach((eachUrl) => {
expect(page.canGoPrevious()).toEqual(true);
page.goPrevious();
browser.getCurrentUrl().then((newUrl) => {
expect(newUrl).toEqual(eachUrl);
});
expect(page.canGoNext()).toEqual(true);
}, this);
});
});
@@ -0,0 +1,144 @@
import { browser, by, element, ElementFinder, protractor } from 'protractor';
import { CreditCardPageOnePo } from './pages/page-one.po';
import { ContactPagePo } from '../shared/pages/contact-page.po';
import { PageObjectTools } from '../shared/page-object-tools';
import { ResidencePagePo } from '../shared/pages/residence-page.po';
import { EmploymentPagePo } from '../shared/pages/employment-page.po';
import { CreditCardDisclosuresPagePo } from './pages/page-disclosures.po';
import { SummaryPagePo } from '../shared/pages/summary-page.po';
describe('It should create a maximum credit card application ', () => {
it('should accept maximum inputs for page 1 (Member/Loan Type)', () => {
const page = new CreditCardPageOnePo();
browser.get(page.PAGE_URL);
browser.sleep(1000);
expect(page.getFocusedElement()).toEqual(page.getFirstElement());
let inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMaximum();
inputArray = PageObjectTools.findFieldsInPageByIdArray([...page.ALL_FIELDS, ...page.HIDDEN_FIELDS_1]);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length + page.HIDDEN_FIELDS_1.length);
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept maximum inputs for page 2 (Personal Info)', () => {
const page = new ContactPagePo();
expect(page.getFocusedElement()).toEqual(page.getFirstElement());
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMaximumCoApplicant();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept maximum inputs for page 3 (Residence)', () => {
const page = new ResidencePagePo();
expect(page.getFocusedElement()).toEqual(page.getFirstElement(page.DEFAULT_PREFIX));
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMinimal();
page.showMailingAddress();
page.showSecondAddress();
page.fillAdditionalFieldsMaximum();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept maximum inputs for page 4 (Employment)', () => {
const page = new EmploymentPagePo();
let inputArray = PageObjectTools.findFieldsInPageByIdArray(page.STARTING_FIELDS);
expect(inputArray.length).toEqual(page.STARTING_FIELDS.length);
expect(page.canGoNext()).toEqual(true);
page.showEmploymentFields();
inputArray = PageObjectTools.findFieldsInPageByIdArray([...page.EMPLOYMENT_FIELDS], page.DEFAULT_PREFIX);
expect(inputArray.length).toEqual([...page.EMPLOYMENT_FIELDS].length);
expect(page.canGoNext()).toEqual(false);
page.showOtherIncomeFields();
page.showChildSupportFields();
page.fillFieldsMaximum();
expect(page.canGoNext()).toEqual(false);
page.fillChildSupportFields();
page.fillOtherIncomeFields();
// page.markSingleIncomeNotEnough();
// Will no longer happen.
// expect(page.canGoNext()).toEqual(false);
// page.fillSecondIncome();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept maximum inputs for page 2.A (Co-Applicant Personal Info)', () => {
const page = new ContactPagePo();
const EC = protractor.ExpectedConditions;
browser.wait(EC.visibilityOf(page.getFirstElement()), 5000).then(() => {});
expect(page.getFocusedElement()).toEqual(page.getFirstElement());
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.COAPP_FIELDS);
expect(inputArray.length).toEqual(page.COAPP_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMaximumCoApplicantNonPrimary();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept maximum inputs for page 3.A (Co-applicant Residence)', () => {
const page = new ResidencePagePo();
page.markAddressNotSame();
expect(page.getFocusedElement()).toEqual(page.getFirstElement(page.DEFAULT_PREFIX));
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMinimal();
page.showMailingAddress();
page.showSecondAddress();
page.fillAdditionalFieldsMaximum();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept maximum inputs for page 4.A (Co-applicant Employment)', () => {
const page = new EmploymentPagePo();
let inputArray = PageObjectTools.findFieldsInPageByIdArray(page.STARTING_FIELDS);
expect(inputArray.length).toEqual(page.STARTING_FIELDS.length);
expect(page.canGoNext()).toEqual(true);
page.showEmploymentFields();
inputArray = PageObjectTools.findFieldsInPageByIdArray([...page.EMPLOYMENT_FIELDS], page.DEFAULT_PREFIX);
expect(inputArray.length).toEqual([...page.EMPLOYMENT_FIELDS].length);
expect(page.canGoNext()).toEqual(false);
page.showOtherIncomeFields();
page.showChildSupportFields();
page.fillFieldsMaximum();
expect(page.canGoNext()).toEqual(false);
page.fillChildSupportFields();
page.fillOtherIncomeFields();
page.markSingleIncomeNotEnough();
// Will no longer happen.
// expect(page.canGoNext()).toEqual(false);
// page.fillSecondIncome();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should maximum inputs for page 5 (Disclosures)', () => {
const page = new CreditCardDisclosuresPagePo();
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMinimal();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should show application information on page 6 (Summary)', () => {
const page = new SummaryPagePo();
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
page.fillFieldsMinimal();
expect(page.canGoNext()).toEqual(true);
});
});
@@ -0,0 +1,85 @@
import { browser, by, element, ElementFinder, protractor } from 'protractor';
import { CreditCardPageOnePo } from './pages/page-one.po';
import { ContactPagePo } from '../shared/pages/contact-page.po';
import { PageObjectTools } from '../shared/page-object-tools';
import { ResidencePagePo } from '../shared/pages/residence-page.po';
import { EmploymentPagePo } from '../shared/pages/employment-page.po';
import { CreditCardDisclosuresPagePo } from './pages/page-disclosures.po';
import { SummaryPagePo } from '../shared/pages/summary-page.po';
describe('It should create a minimal credit card application ', () => {
it('should accept basic inputs for page 1 (Member/Loan Type)', () => {
const page = new CreditCardPageOnePo();
browser.get(page.PAGE_URL);
browser.sleep(1000);
expect(page.getFocusedElement()).toEqual(page.getFirstElement());
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMinimal();
expect(page.canGoNext()).toEqual(true);
page.fillFieldsForFailureToConfirmJointCredit();
expect(page.canGoNext()).toEqual(false);
page.dismissModalByOkayButton();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept basic inputs for page 2 (Personal Info)', () => {
const page = new ContactPagePo();
expect(page.getFocusedElement()).toEqual(page.getFirstElement());
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMinimal();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept basic inputs for page 3 (Residence)', () => {
const page = new ResidencePagePo();
expect(page.getFocusedElement()).toEqual(page.getFirstElement(page.DEFAULT_PREFIX));
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMinimal();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept basic inputs for page 4 (Employment)', () => {
const page = new EmploymentPagePo();
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.STARTING_FIELDS);
expect(inputArray.length).toEqual(page.STARTING_FIELDS.length);
// For a minimal credit card, don't enter any income :-)
// expect(page.canGoNext()).toEqual(false);
// page.showEmploymentFields();
// inputArray = PageObjectTools.findFieldsInPageByIdArray([...page.EMPLOYMENT_FIELDS], page.DEFAULT_PREFIX);
// expect(inputArray.length).toEqual([...page.EMPLOYMENT_FIELDS].length);
// expect(page.canGoNext()).toEqual(false);
// page.fillFieldsMinimal();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept basic inputs for page 5 (Disclosures)', () => {
const page = new CreditCardDisclosuresPagePo();
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMinimal();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should show application information on page 6 (Summary)', () => {
const page = new SummaryPagePo();
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
page.fillFieldsMinimal();
expect(page.canGoNext()).toEqual(true);
});
// We could go to the next page, but we'd create X loans every time we run these tests...
});
@@ -0,0 +1,130 @@
import { browser, by, element, ElementFinder, protractor } from 'protractor';
import { CreditCardPageOnePo } from './pages/page-one.po';
import { ContactPagePo } from '../shared/pages/contact-page.po';
import { PageObjectTools } from '../shared/page-object-tools';
import { ResidencePagePo } from '../shared/pages/residence-page.po';
import { EmploymentPagePo } from '../shared/pages/employment-page.po';
import { CreditCardDisclosuresPagePo } from './pages/page-disclosures.po';
import { SummaryPagePo } from '../shared/pages/summary-page.po';
import { SpouseTypePagePo } from '../shared/pages/spouse-type-page.po';
import { TattleSpousePagePo } from '../shared/pages/tattle-spouse-page.po';
describe('It should create a credit card application for 2 full info individuals + 2 tattle spouses', () => {
it('should accept maximum inputs for page 1 (Member/Loan Type)', () => {
const page = new CreditCardPageOnePo();
browser.get(page.PAGE_URL);
browser.sleep(1000);
expect(page.getFocusedElement()).toEqual(page.getFirstElement());
let inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMaximum();
inputArray = PageObjectTools.findFieldsInPageByIdArray([...page.ALL_FIELDS, ...page.HIDDEN_FIELDS_1]);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length + page.HIDDEN_FIELDS_1.length);
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept minimum inputs for page 2.A (Personal Info)', () => {
const page = new ContactPagePo();
expect(page.getFocusedElement()).toEqual(page.getFirstElement());
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsPrimaryMarriedButNotMarriedToCoApplicant();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept minimum inputs for page 3.A (Residence)', () => {
const page = new ResidencePagePo();
expect(page.getFocusedElement()).toEqual(page.getFirstElement(page.DEFAULT_PREFIX));
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMinimalLivingInWI();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept minimum inputs for page 4.A (Employment)', () => {
const page = new EmploymentPagePo();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept TATTLE SPOUSE input for Applicant spouse type page', () => {
const page = new SpouseTypePagePo();
expect(page.canGoNext()).toEqual(false);
page.fillFieldsTattleSpouse();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept minimum inputs for tattle spouse page (Applicant\'s Spouse Tattle Info)', () => {
const page = new TattleSpousePagePo();
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMinimal();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept maximum inputs for page 2.C (Co-Applicant Personal Info)', () => {
const page = new ContactPagePo();
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMaximumCoApplicantNonPrimary();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept minimum inputs for page 3.C (Co-applicant Residence)', () => {
const page = new ResidencePagePo();
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMinimalLivingInWI();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept minimum inputs for page 4.C (Co-applicant Employment)', () => {
const page = new EmploymentPagePo();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept TATTLE SPOUSE input for CoApplicant spouse type page', () => {
const page = new SpouseTypePagePo();
expect(page.canGoNext()).toEqual(false);
page.fillFieldsTattleSpouse();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept minimum inputs for tattle spouse page (CoApplicant\'s Spouse Tattle Info)', () => {
const page = new TattleSpousePagePo();
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMinimal();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should maximum inputs for page 5 (Disclosures)', () => {
const page = new CreditCardDisclosuresPagePo();
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMinimal();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should show application information on page 6 (Summary)', () => {
const page = new SummaryPagePo();
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
page.fillFieldsMinimal();
expect(page.canGoNext()).toEqual(true);
});
});
@@ -0,0 +1,34 @@
import { browser, by, element, ElementFinder, protractor, promise } from 'protractor';
import { PageObjectTools } from '../../shared/page-object-tools';
export class CreditCardDisclosuresPagePo {
public readonly PAGE_URL = '/loan-wizard/cc/cb/disclosures';
public readonly DISCLOSE_TRUTHFUL = 'truthful';
public readonly DISCLOSE_CONTACT = 'contact';
public readonly NEXT_BUTTON = 'buttonNext';
public readonly ALL_FIELDS = [
this.DISCLOSE_TRUTHFUL, this.DISCLOSE_CONTACT,
this.NEXT_BUTTON];
public canGoNext(): promise.Promise<boolean> {
const nextButton = element(by.id(this.NEXT_BUTTON));
if (nextButton) {
return nextButton.isEnabled();
}
throw new Error('Couldn\'t get next button');
}
public submit(): void {
const nextButton = element(by.id(this.NEXT_BUTTON));
nextButton.click();
}
public fillFieldsMinimal(): void {
const truthful = element(by.id(this.DISCLOSE_TRUTHFUL));
PageObjectTools.clickCheckBox(truthful);
}
}
@@ -0,0 +1,77 @@
import { browser, by, element, ElementFinder, protractor, promise } from 'protractor';
import { PageObjectTools } from '../../shared/page-object-tools';
import { TestInputSet, TestInputCommand, TestingInputType } from '../../shared/data-driven/test-input-command';
export class CreditCardPageOnePo {
public readonly PAGE_URL = '/loan-wizard/cc/cb/step-1';
public readonly LIMIT_REQUESTED = 'inputLimitRequested';
public readonly ANOTHER_PERSON = 'inputApplicantType';
public readonly LIVE_IN_WI = 'inputLivesInMaritalPropertyState';
public readonly JOINT_CREDIT = 'inputConfirmJointCredit';
public readonly CO_APP_LIVE_IN_WI = 'inputCoAppLivesInMaritalPropertyState';
public readonly NEXT_BUTTON = 'buttonNext';
public readonly MODAL_CLOSE_BUTTON = 'modalCloseButton';
public readonly MODAL_OKAY_BUTTON = 'modalOkayButton';
public readonly ALL_FIELDS = [this.LIMIT_REQUESTED, this.ANOTHER_PERSON, this.LIVE_IN_WI, this.NEXT_BUTTON];
public readonly HIDDEN_FIELDS_1 = [this.JOINT_CREDIT, this.CO_APP_LIVE_IN_WI];
public readonly MINIMAL_DATA: TestInputSet = [
{ fieldId: this.LIMIT_REQUESTED, fieldValue: 1234, fieldType: TestingInputType.TEXT },
{ fieldId: this.ANOTHER_PERSON, fieldValue: 1, fieldType: TestingInputType.RADIO },
{ fieldId: this.LIVE_IN_WI, fieldValue: 1, fieldType: TestingInputType.RADIO }
];
public readonly MAXIMUM_DATA: TestInputSet = [
{ fieldId: this.LIMIT_REQUESTED, fieldValue: 1234, fieldType: TestingInputType.TEXT },
{ fieldId: this.ANOTHER_PERSON, fieldValue: 0, fieldType: TestingInputType.RADIO },
{ fieldId: this.LIVE_IN_WI, fieldValue: 0, fieldType: TestingInputType.RADIO },
{ fieldId: this.JOINT_CREDIT, fieldValue: 0, fieldType: TestingInputType.RADIO },
{ fieldId: this.CO_APP_LIVE_IN_WI, fieldValue: 0, fieldType: TestingInputType.RADIO }
];
public readonly JOINT_CREDIT_DATA: TestInputSet = [
{ fieldId: this.ANOTHER_PERSON, fieldValue: 0, fieldType: TestingInputType.RADIO },
{ fieldId: this.JOINT_CREDIT, fieldValue: 1, fieldType: TestingInputType.RADIO }
];
public canGoNext(): promise.Promise<boolean> {
const nextButton = element(by.id(this.NEXT_BUTTON));
if (nextButton) {
return nextButton.isEnabled();
}
throw new Error('Couldn\'t get next button');
}
public submit(): void {
const nextButton = element(by.id(this.NEXT_BUTTON));
nextButton.click();
}
public fillFieldsForFailureToConfirmJointCredit(): void {
PageObjectTools.fillFields(this.JOINT_CREDIT_DATA);
}
public dismissModalByOkayButton(): void {
const modalOkayButton = element(by.id(this.MODAL_OKAY_BUTTON));
modalOkayButton.click();
}
public fillFieldsMinimal(): void {
PageObjectTools.fillFields(this.MINIMAL_DATA);
}
public fillFieldsMaximum(): void {
PageObjectTools.fillFields(this.MAXIMUM_DATA);
}
public getFocusedElement() {
return PageObjectTools.getFocusedElement();
}
public getFirstElement() {
return PageObjectTools.getElementsIdField(this.LIMIT_REQUESTED);
}
}
@@ -0,0 +1,177 @@
import { browser, protractor } from 'protractor';
import { PageObjectTools } from '../shared/page-object-tools';
import { HelocPageOnePo } from './pages/page-one.po';
import { ContactPagePo } from '../shared/pages/contact-page.po';
import { EmploymentPagePo } from '../shared/pages/employment-page.po';
import { ResidencePagePo } from '../shared/pages/residence-page.po';
import { HmdaPagePo } from '../shared/pages/hmda-page.po';
import { CollateralPagePo } from '../shared/pages/collateral-page.po';
import { SummaryPagePo } from '../shared/pages/summary-page.po';
import { CreditCardDisclosuresPagePo } from '../credit-card/pages/page-disclosures.po';
describe('It should create a maximum HELOC application ', () => {
it('should accept maximum inputs for page 1 (Member/Loan Type)', () => {
const page = new HelocPageOnePo();
browser.get(page.PAGE_URL);
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMaximum();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept maximum inputs for page 2 (Personal Info)', () => {
const page = new ContactPagePo();
expect(page.getFocusedElement()).toEqual(page.getFirstElement());
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMaximumCoApplicant();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept maximum inputs for page 3 (Residence)', () => {
const page = new ResidencePagePo();
expect(page.getFocusedElement()).toEqual(page.getFirstElement(page.DEFAULT_PREFIX));
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMinimal();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept maximum inputs for HMDA page (HMDA: Race/Ethnicity/Gender)', () => {
const page = new HmdaPagePo();
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMaximum();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept maximum inputs for page 4 (Employment)', () => {
const page = new EmploymentPagePo();
let inputArray = PageObjectTools.findFieldsInPageByIdArray(page.STARTING_FIELDS, page.DEFAULT_PREFIX);
expect(inputArray.length).toEqual(page.STARTING_FIELDS.length);
expect(page.canGoNext()).toEqual(true);
page.showEmploymentFields();
inputArray = PageObjectTools.findFieldsInPageByIdArray([...page.STARTING_FIELDS, ...page.EMPLOYMENT_FIELDS], page.DEFAULT_PREFIX);
expect(inputArray.length).toEqual([...page.STARTING_FIELDS, ...page.EMPLOYMENT_FIELDS].length);
expect(page.canGoNext()).toEqual(false);
page.showOtherIncomeFields();
page.showChildSupportFields();
page.fillFieldsMaximum();
expect(page.canGoNext()).toEqual(false);
page.fillChildSupportFields();
page.fillOtherIncomeFields();
page.markSingleIncomeNotEnough();
// Will no longer happen.
// expect(page.canGoNext()).toEqual(false);
// page.fillSecondIncome();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept maximum inputs for page 2.A (Co-Applicant Personal Info)', () => {
const page = new ContactPagePo();
const EC = protractor.ExpectedConditions;
browser.wait(EC.visibilityOf(page.getFirstElement()), 5000).then(() => {});
expect(page.getFocusedElement()).toEqual(page.getFirstElement());
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.COAPP_FIELDS);
expect(inputArray.length).toEqual(page.COAPP_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMaximumCoApplicantNonPrimary();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept maximum inputs for page 3.A (Co-applicant Residence)', () => {
const page = new ResidencePagePo();
page.markAddressNotSame();
expect(page.getFocusedElement()).toEqual(page.getFirstElement(page.DEFAULT_PREFIX));
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMinimal();
page.showMailingAddress();
page.showSecondAddress();
page.fillAdditionalFieldsMaximum();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept maximum inputs for co-applicant HMDA page (Co-applicant HMDA: Race/Ethnicity/Gender)', () => {
const page = new HmdaPagePo();
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMaximum();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept maximum inputs for page 4.A (Co-applicant Employment)', () => {
const page = new EmploymentPagePo();
let inputArray = PageObjectTools.findFieldsInPageByIdArray(page.STARTING_FIELDS);
expect(inputArray.length).toEqual(page.STARTING_FIELDS.length);
expect(page.canGoNext()).toEqual(true);
page.showEmploymentFields();
inputArray = PageObjectTools.findFieldsInPageByIdArray([...page.EMPLOYMENT_FIELDS], page.DEFAULT_PREFIX);
expect(inputArray.length).toEqual([...page.EMPLOYMENT_FIELDS].length);
expect(page.canGoNext()).toEqual(false);
page.showOtherIncomeFields();
page.showChildSupportFields();
page.fillFieldsMaximum();
expect(page.canGoNext()).toEqual(false);
page.fillChildSupportFields();
page.fillOtherIncomeFields();
page.markSingleIncomeNotEnough();
// Will no longer happen.
// expect(page.canGoNext()).toEqual(false);
// page.fillSecondIncome();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept maximum inputs for collateral page (Collateral)', () => {
const page = new CollateralPagePo();
const EC = protractor.ExpectedConditions;
browser.wait(EC.visibilityOf(page.getFirstElement()), 5000).then(() => {});
expect(page.getFocusedElement()).toEqual(page.getFirstElement());
let inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
inputArray = PageObjectTools.findFieldsInPageByIdArray([...page.ALL_FIELDS, ...page.ADDRESS_FIELDS, ...page.LIEN_POSITION_FIELDS]);
expect(inputArray.length).toEqual([...page.ALL_FIELDS, ...page.ADDRESS_FIELDS, ...page.LIEN_POSITION_FIELDS].length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMaximum();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept maximum inputs for page 5 (Disclosures)', () => {
const page = new CreditCardDisclosuresPagePo();
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMinimal();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should show application information on page 6 (Summary)', () => {
const page = new SummaryPagePo();
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
page.fillFieldsMinimal();
expect(page.canGoNext()).toEqual(true);
});
});
@@ -0,0 +1,99 @@
import { browser, by, element, ElementFinder, protractor } from 'protractor';
import { PageObjectTools } from '../shared/page-object-tools';
import { HelocPageOnePo } from './pages/page-one.po';
import { ContactPagePo } from '../shared/pages/contact-page.po';
import { EmploymentPagePo } from '../shared/pages/employment-page.po';
import { ResidencePagePo } from '../shared/pages/residence-page.po';
import { HmdaPagePo } from '../shared/pages/hmda-page.po';
import { CollateralPagePo } from '../shared/pages/collateral-page.po';
import { SummaryPagePo } from '../shared/pages/summary-page.po';
import { CreditCardDisclosuresPagePo } from '../credit-card/pages/page-disclosures.po';
describe('It should create a minimal HELOC application ', () => {
it('should accept basic inputs for page 1 (Member/Loan Type)', () => {
const page = new HelocPageOnePo();
browser.get(page.PAGE_URL);
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMinimal();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept basic inputs for page 2 (Personal Info)', () => {
const page = new ContactPagePo();
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMinimal();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept basic inputs for page 3 (Residence)', () => {
const page = new ResidencePagePo();
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMinimal();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept basic inputs for page 3.A (HMDA: Race/Ethnicity/Gender)', () => {
const page = new HmdaPagePo();
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMinimal();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept basic inputs for page 4 (Employment)', () => {
const page = new EmploymentPagePo();
let inputArray = PageObjectTools.findFieldsInPageByIdArray(page.STARTING_FIELDS, page.DEFAULT_PREFIX);
expect(inputArray.length).toEqual(page.STARTING_FIELDS.length);
expect(page.canGoNext()).toEqual(true);
page.showEmploymentFields();
inputArray = PageObjectTools.findFieldsInPageByIdArray([...page.STARTING_FIELDS, ...page.EMPLOYMENT_FIELDS], page.DEFAULT_PREFIX);
expect(inputArray.length).toEqual([...page.STARTING_FIELDS, ...page.EMPLOYMENT_FIELDS].length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMinimal();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept basic inputs for page 4.A (Collateral)', () => {
const page = new CollateralPagePo();
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMinimal();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept basic inputs for page 5 (Disclosures)', () => {
const page = new CreditCardDisclosuresPagePo();
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMinimal();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should show application information on page 6 (Summary)', () => {
const page = new SummaryPagePo();
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
page.fillFieldsMinimal();
expect(page.canGoNext()).toEqual(true);
});
});
@@ -0,0 +1,56 @@
import { by, element, promise } from 'protractor';
import { PageObjectTools } from '../../shared/page-object-tools';
import { TestInputSet, TestingInputType } from '../../shared/data-driven/test-input-command';
export class HelocPageOnePo {
public readonly PAGE_URL = '/loan-wizard/eq/he/step-1';
public readonly LIMIT_REQUESTED = 'inputLimitRequested';
public readonly ANOTHER_PERSON = 'inputApplicantType';
public readonly LIVE_IN_WI = 'inputLivesInMaritalPropertyState';
public readonly JOINT_CREDIT = 'inputConfirmJointCredit';
public readonly CO_APP_LIVE_IN_WI = 'inputCoAppLivesInMaritalPropertyState';
public readonly PURPOSE_OF_LOAN = 'inputPurposeOfLoan';
public readonly NEXT_BUTTON = 'buttonNext';
public readonly ALL_FIELDS = [this.LIMIT_REQUESTED, this.ANOTHER_PERSON, this.LIVE_IN_WI, this.NEXT_BUTTON, this.PURPOSE_OF_LOAN];
public readonly HIDDEN_FIELDS_1 = [this.JOINT_CREDIT, this.CO_APP_LIVE_IN_WI];
public readonly MINIMAL_DATA: TestInputSet = [
{ fieldId: this.LIMIT_REQUESTED, fieldValue: 5432, fieldType: TestingInputType.TEXT },
{ fieldId: this.ANOTHER_PERSON, fieldValue: 1, fieldType: TestingInputType.RADIO },
{ fieldId: this.LIVE_IN_WI, fieldValue: 1, fieldType: TestingInputType.RADIO },
{ fieldId: this.PURPOSE_OF_LOAN, fieldValue: 1, fieldType: TestingInputType.SELECT }
];
public readonly MAXIMUM_DATA: TestInputSet = [
{ fieldId: this.LIMIT_REQUESTED, fieldValue: 5432, fieldType: TestingInputType.TEXT },
{ fieldId: this.ANOTHER_PERSON, fieldValue: 0, fieldType: TestingInputType.RADIO },
{ fieldId: this.LIVE_IN_WI, fieldValue: 0, fieldType: TestingInputType.RADIO },
{ fieldId: this.JOINT_CREDIT, fieldValue: 0, fieldType: TestingInputType.RADIO },
{ fieldId: this.CO_APP_LIVE_IN_WI, fieldValue: 0, fieldType: TestingInputType.RADIO },
{ fieldId: this.PURPOSE_OF_LOAN, fieldValue: 2, fieldType: TestingInputType.SELECT }
];
public canGoNext(): promise.Promise<boolean> {
const nextButton = element(by.id(this.NEXT_BUTTON));
if (nextButton) {
return nextButton.isEnabled();
}
throw new Error('Couldn\'t get next button');
}
public submit(): void {
const nextButton = element(by.id(this.NEXT_BUTTON));
nextButton.click();
}
public fillFieldsMinimal(): void {
PageObjectTools.fillFields(this.MINIMAL_DATA);
}
public fillFieldsMaximum(): void {
PageObjectTools.fillFields(this.MAXIMUM_DATA);
}
}
@@ -0,0 +1,10 @@
import { SelectLoanPo } from './select-loan.po';
export class SelectLoanCreditPo extends SelectLoanPo {
public readonly PAGE_URL = '/select-loan/credit-card';
public readonly CASH_BACK = 'cc-cash';
public readonly REWARDS = 'cc-reward';
public readonly STUDENT = 'cc-student';
public readonly SECURED = 'cc-secured';
}
@@ -0,0 +1,11 @@
import { SelectLoanPo } from './select-loan.po';
export class SelectLoanHomePo extends SelectLoanPo {
public readonly PAGE_URL = '/select-loan/home-equity';
public readonly HELOC = 'eq-heloc';
public readonly HOME_EQUITY = 'eq-fixed';
public readonly MORT_REFI = 'eq-refi';
public readonly MANU_HOME = 'eq-manu';
}
@@ -0,0 +1,7 @@
import { SelectLoanPo } from './select-loan.po';
export class SelectLoanPersonalPo extends SelectLoanPo {
public readonly PAGE_URL = '/loan-wizard/sl/pe';
}
@@ -0,0 +1,9 @@
import { SelectLoanPo } from './select-loan.po';
export class SelectLoanVehicleSubPo extends SelectLoanPo {
public PAGE_URL = '/select-loan/sub-vehicle';
public readonly LOAN = 've-loan';
public readonly PRE = 've-pre';
}
@@ -0,0 +1,11 @@
import { SelectLoanPo } from './select-loan.po';
export class SelectLoanVehiclePo extends SelectLoanPo {
public readonly PAGE_URL = '/select-loan/vehicle';
public readonly AUTO = 've-sub';
public readonly BOAT = 've-boat';
public readonly POWERSPORTS = 've-power';
public readonly TRAILER = 've-trailer';
}
@@ -0,0 +1,42 @@
import {browser, by, element } from 'protractor';
export class SelectLoanPo {
public PAGE_URL = '/';
public readonly CREDIT_CARD_CARD = 'cc-card';
public readonly HOME_EQUITY_CARD = 'he-card';
public readonly VEHICLE_CARD = 've-card';
public readonly PERSONAL_CARD = 'pe-card';
public readonly PREVIOUS_BUTTON = 'previous';
navigateTo() {
return browser.get(this.PAGE_URL);
}
getHeaderBar() {
return element(by.css('lw-navigation'));
}
getPageTitle() {
return browser.getTitle();
}
getTextByClassName(className: string) {
return element(by.className(className)).getText();
}
isElementEnabled(eId: string) {
return element(by.id(eId)).isEnabled();
}
clickCard(eId: string): void {
const card = element(by.id(eId));
card.click();
}
goPrevious(): void {
const nextButton = element(by.id(this.PREVIOUS_BUTTON));
nextButton.click();
}
}
@@ -0,0 +1,107 @@
import { SelectLoanPo } from './pages/select-loan.po';
import { SelectLoanCreditPo } from './pages/select-loan-credit.po';
import { browser } from 'protractor';
import { SelectLoanVehiclePo } from './pages/select-loan-vehicle.po';
import { SelectLoanHomePo } from './pages/select-loan-home.po';
import { SelectLoanPersonalPo } from './pages/select-loan-personal.po';
import { SelectLoanVehicleSubPo } from './pages/select-loan-vehicle-sub.po';
describe('Select Loan', () => {
const landingPage = new SelectLoanPo();
it('should display landing page with correct text and cards', () => {
landingPage.navigateTo();
expect(landingPage.getHeaderBar()).toBeDefined();
const text = landingPage.getTextByClassName('loan-header');
expect(text).toEqual('Start a new loan application');
expect(landingPage.isElementEnabled(landingPage.CREDIT_CARD_CARD)).toEqual(true);
expect(landingPage.isElementEnabled(landingPage.HOME_EQUITY_CARD)).toEqual(true);
expect(landingPage.isElementEnabled(landingPage.PERSONAL_CARD)).toEqual(true);
expect(landingPage.isElementEnabled(landingPage.VEHICLE_CARD)).toEqual(true);
landingPage.clickCard(landingPage.CREDIT_CARD_CARD);
});
it('should display credit card landing page with correct text and cards', () => {
const page = new SelectLoanCreditPo();
expect(page.getHeaderBar()).toBeDefined();
const text = page.getTextByClassName('loan-header');
expect(text).toEqual('Select a credit card type');
expect(page.isElementEnabled(page.CASH_BACK)).toEqual(true);
expect(page.isElementEnabled(page.REWARDS)).toEqual(true);
expect(page.isElementEnabled(page.SECURED)).toEqual(true);
expect(page.isElementEnabled(page.STUDENT)).toEqual(true);
page.clickCard(page.CASH_BACK);
browser.navigate().back();
page.clickCard(page.REWARDS);
browser.navigate().back();
page.clickCard(page.SECURED);
browser.navigate().back();
page.clickCard(page.STUDENT);
browser.navigate().back();
page.goPrevious();
landingPage.clickCard(landingPage.VEHICLE_CARD);
});
it('should display vehicle landing page with correct text and cards', () => {
const page = new SelectLoanVehiclePo();
expect(page.getHeaderBar()).toBeDefined();
const text = page.getTextByClassName('loan-header');
expect(text).toEqual('Select a vehicle type');
expect(page.isElementEnabled(page.BOAT)).toEqual(true);
expect(page.isElementEnabled(page.POWERSPORTS)).toEqual(true);
expect(page.isElementEnabled(page.TRAILER)).toEqual(true);
expect(page.isElementEnabled(page.AUTO)).toEqual(true);
page.clickCard(page.BOAT);
browser.navigate().back();
page.clickCard(page.POWERSPORTS);
browser.navigate().back();
page.clickCard(page.TRAILER);
browser.navigate().back();
page.clickCard(page.AUTO);
});
it('should display vehicle sub landing page with correct text and cards', () => {
const page = new SelectLoanVehicleSubPo();
expect(page.getHeaderBar()).toBeDefined();
const text = page.getTextByClassName('loan-header');
expect(text).toEqual('Select a vehicle type');
expect(page.isElementEnabled(page.LOAN)).toEqual(true);
expect(page.isElementEnabled(page.PRE)).toEqual(true);
page.clickCard(page.LOAN);
browser.navigate().back();
page.clickCard(page.PRE);
browser.navigate().back();
page.goPrevious();
page.goPrevious();
landingPage.clickCard(landingPage.HOME_EQUITY_CARD);
});
it('should display home equity landing page with correct text and cards', () => {
const page = new SelectLoanHomePo();
expect(page.getHeaderBar()).toBeDefined();
const text = page.getTextByClassName('loan-header');
expect(text).toEqual('Select a home equity type');
expect(page.isElementEnabled(page.HOME_EQUITY)).toEqual(true);
expect(page.isElementEnabled(page.MANU_HOME)).toEqual(true);
expect(page.isElementEnabled(page.MORT_REFI)).toEqual(true);
expect(page.isElementEnabled(page.HELOC)).toEqual(true);
page.clickCard(page.HOME_EQUITY);
browser.navigate().back();
page.clickCard(page.MANU_HOME);
browser.navigate().back();
page.clickCard(page.MORT_REFI);
browser.navigate().back();
page.clickCard(page.HELOC);
browser.navigate().back();
page.goPrevious();
landingPage.clickCard(landingPage.PERSONAL_CARD);
});
it('should start personal loan ', () => {
const page = new SelectLoanPersonalPo();
expect(page.getHeaderBar()).toBeDefined();
browser.navigate().back();
expect(landingPage.getHeaderBar()).toBeDefined();
});
});
@@ -0,0 +1,12 @@
export enum TestingInputType {
TEXT, SELECT, CHECK, RADIO
}
export interface TestInputCommand {
fieldId: string;
fieldValue: any;
fieldType: TestingInputType;
}
export type TestInputSet = Array<TestInputCommand>;
@@ -0,0 +1,22 @@
export class PageDataTools {
public static readonly numbersList = '1234567890';
public static readonly alphabetList = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
public static createRandomEmail(startLength = 10, endLength = 10): string {
const begin = this.createRandomString(startLength);
const end = this.createRandomString(endLength);
const email = [begin, '@', end, '.com'];
return email.join('');
}
public static createRandomString(stringLength: number) {
const characters = this.alphabetList;
let result = '';
for (let j = stringLength; j > 0; --j) {
result += characters[Math.floor(Math.random() * characters.length)];
}
return result;
}
}
@@ -0,0 +1,87 @@
import { browser, by, element, ElementFinder, protractor, promise } from 'protractor';
import { TestingInputType, TestInputCommand, TestInputSet } from './data-driven/test-input-command';
export class PageObjectTools {
public static urlChanged(url): any {
return function () {
return browser.getCurrentUrl().then(function (actualUrl) {
return url !== actualUrl;
});
};
}
public static fillFields(dataSet: TestInputSet, prefix?: string): void {
dataSet.forEach((command: TestInputCommand) => {
PageObjectTools.executeTestInputCommand(command, prefix);
}, this);
}
static executeTestInputCommand(command: TestInputCommand, prefix?: string): any {
const fullId = prefix ? prefix + command.fieldId : command.fieldId;
const currentField = element(by.id(fullId));
if (!currentField || !currentField.isDisplayed()) {
throw new Error('Couldn\'t execute command, field not found: ' + fullId);
}
switch (command.fieldType) {
default:
throw new Error('You must specify a field type for field Id: ' + fullId);
case TestingInputType.TEXT:
currentField.sendKeys(command.fieldValue);
break;
case TestingInputType.SELECT:
PageObjectTools.selectDropDownField(currentField, command.fieldValue);
break;
case TestingInputType.CHECK:
PageObjectTools.clickCheckBox(currentField);
break;
case TestingInputType.RADIO:
PageObjectTools.selectRadioButton(currentField, command.fieldValue);
break;
}
}
public static findFieldsInPageByIdArray(fieldsIdSet: Array<string>, prefix?: string) {
let foundField = null;
const usedPrefix = prefix || '';
const allFields = [];
fieldsIdSet.forEach((fieldId, index) => {
foundField = element(by.id(usedPrefix + fieldId));
if (foundField) {
allFields.push(foundField);
}
});
return allFields;
}
public static selectDropDownField(elementFinder: ElementFinder, optionNumber: number) {
const desiredOption = elementFinder.all(by.tagName('option')).get(optionNumber);
const EC = protractor.ExpectedConditions;
browser.wait(EC.visibilityOf(desiredOption), 5000).then(() => {
desiredOption.click();
});
}
public static selectRadioButton(elementFinder: ElementFinder, optionNumber: number) {
const desiredOption = elementFinder.all(by.tagName('label')).get(optionNumber);
const EC = protractor.ExpectedConditions;
browser.wait(EC.visibilityOf(desiredOption), 5000).then(() => {
desiredOption.click();
});
}
static clickCheckBox(checkbox: ElementFinder) {
browser.executeScript('arguments[0].click();', checkbox.getWebElement());
}
public static getElementsIdField(fieldId: string, prefix?: string): any {
const firstElement = element( by.id( prefix ? prefix + fieldId : fieldId));
return firstElement.getAttribute( 'id' );
}
public static getFocusedElement(): any {
return browser.driver.switchTo().activeElement().getAttribute('id');
}
}
@@ -0,0 +1,88 @@
import { by, element, promise } from 'protractor';
import { PageObjectTools } from '../page-object-tools';
import { TestInputSet, TestingInputType } from '../data-driven/test-input-command';
export class CollateralPagePo {
public readonly ESTIMATED_VALUE = '-inputEstimatedValue';
public readonly PROPERTY_TYPE = '-inputPropertyType';
public readonly HAS_FIRST_MORTGAGE = 'inputFirstMortgage';
public readonly HAS_SECOND_MORTGAGE = 'inputSecondMortgage';
public readonly PAYOFF_FIRST_MORTGAGE = 'payoffFirstMortgage';
public readonly PAYOFF_SECOND_MORTGAGE = 'payoffSecondMortgage';
public readonly IS_SAME_ADDRESS = 'isAddressSame';
public readonly IS_BEING_IMPROVED = 'inputBeingImproved';
public readonly IS_LISTED_FOR_SALE = 'inputListedForSale';
// address information
public readonly ADDRESS_1 = '-inputAddress1';
public readonly ADDRESS_2 = '-inputAddress2';
public readonly CITY = '-inputCity';
public readonly STATE = '-inputState';
public readonly ZIP = '-inputZip';
public readonly OCCUPANCY_TYPE = '-inputOccupancyType';
public readonly NEXT_BUTTON = 'buttonNext';
public readonly ALL_FIELDS = [this.ESTIMATED_VALUE, this.PROPERTY_TYPE,
this.IS_SAME_ADDRESS, this.IS_BEING_IMPROVED, this.IS_LISTED_FOR_SALE, this.NEXT_BUTTON];
public readonly ADDRESS_FIELDS = [ this.OCCUPANCY_TYPE, this.ADDRESS_1, this.ADDRESS_2, this.CITY, this.STATE, this.ZIP];
public readonly LIEN_POSITION_FIELDS = [ this.HAS_FIRST_MORTGAGE, this.HAS_SECOND_MORTGAGE, this.PAYOFF_FIRST_MORTGAGE,this.PAYOFF_SECOND_MORTGAGE];
public readonly MINIMAL_DATA: TestInputSet = [
{ fieldId: this.IS_SAME_ADDRESS, fieldValue: 0, fieldType: TestingInputType.RADIO },
{ fieldId: this.IS_BEING_IMPROVED, fieldValue: 0, fieldType: TestingInputType.RADIO },
{ fieldId: this.IS_LISTED_FOR_SALE, fieldValue: 0, fieldType: TestingInputType.RADIO },
{ fieldId: this.ESTIMATED_VALUE, fieldValue: '12345', fieldType: TestingInputType.TEXT },
{ fieldId: this.PROPERTY_TYPE, fieldValue: 2, fieldType: TestingInputType.SELECT },
{ fieldId: this.HAS_FIRST_MORTGAGE, fieldValue: 0, fieldType: TestingInputType.RADIO },
{ fieldId: this.HAS_SECOND_MORTGAGE, fieldValue: 0, fieldType: TestingInputType.RADIO }
];
public readonly MAXIMUM_DATA: TestInputSet = [
{ fieldId: this.IS_SAME_ADDRESS, fieldValue: 1, fieldType: TestingInputType.RADIO },
{ fieldId: this.ADDRESS_1, fieldValue: '1000 South 8th Pl.', fieldType: TestingInputType.TEXT },
{ fieldId: this.CITY, fieldValue: 'Codeville', fieldType: TestingInputType.TEXT },
{ fieldId: this.STATE, fieldValue: 40, fieldType: TestingInputType.SELECT },
{ fieldId: this.ZIP, fieldValue: 53207, fieldType: TestingInputType.TEXT },
{ fieldId: this.IS_BEING_IMPROVED, fieldValue: 0, fieldType: TestingInputType.RADIO },
{ fieldId: this.IS_LISTED_FOR_SALE, fieldValue: 0, fieldType: TestingInputType.RADIO },
{ fieldId: this.OCCUPANCY_TYPE, fieldValue: 2, fieldType: TestingInputType.SELECT },
{ fieldId: this.ESTIMATED_VALUE, fieldValue: '12345', fieldType: TestingInputType.TEXT },
{ fieldId: this.PROPERTY_TYPE, fieldValue: 2, fieldType: TestingInputType.SELECT },
{ fieldId: this.HAS_FIRST_MORTGAGE, fieldValue: 0, fieldType: TestingInputType.RADIO },
{ fieldId: this.HAS_SECOND_MORTGAGE, fieldValue: 0, fieldType: TestingInputType.RADIO },
{ fieldId: this.PAYOFF_FIRST_MORTGAGE, fieldValue: 0, fieldType: TestingInputType.CHECK },
{ fieldId: this.PAYOFF_SECOND_MORTGAGE, fieldValue: 0, fieldType: TestingInputType.CHECK },
];
public canGoNext(): promise.Promise<boolean> {
const nextButton = element(by.id(this.NEXT_BUTTON));
if (nextButton) {
return nextButton.isEnabled();
}
throw new Error('Couldn\'t get next button');
}
public submit(): void {
const nextButton = element(by.id(this.NEXT_BUTTON));
nextButton.click();
}
public fillFieldsMinimal(): void {
PageObjectTools.fillFields(this.MINIMAL_DATA);
}
public fillFieldsMaximum(): void {
PageObjectTools.fillFields(this.MAXIMUM_DATA);
}
public getFocusedElement() {
return PageObjectTools.getFocusedElement();
}
public getFirstElement() {
// it focuses on the yes/no radio, not the overall input
return PageObjectTools.getElementsIdField('isSameYes');
}
}
@@ -0,0 +1,125 @@
import { browser, by, element, ElementFinder, protractor, promise } from 'protractor';
import { PageObjectTools } from '../page-object-tools';
import { PageDataTools } from '../page-data-tools';
import { TestInputSet, TestingInputType } from '../data-driven/test-input-command';
export class ContactPagePo {
public readonly FIRST_NAME = 'inputFirstName';
public readonly MIDDLE_INITIAL = 'inputMiddleInitial';
public readonly LAST_NAME = 'inputLastName';
public readonly DOB = 'inputDOB';
public readonly SUFFIX = 'inputSuffix';
public readonly SSN = 'inputSSN';
public readonly PRIMARY_PHONE = 'inputPrimaryPhoneNumber';
public readonly PRIMARY_PHONE_TYPE = 'inputPrimaryPhoneType';
public readonly SECONDARY_PHONE = 'inputSecondaryPhoneNumber';
public readonly SECONDARY_PHONE_TYPE = 'inputSecondaryPhoneType';
public readonly EMAIL = 'inputEmail';
public readonly MARITAL_STATUS = 'inputMaritalStatus';
public readonly CO_APPLICANT_SPOUSE = 'inputCoApplicantSpouse';
public readonly NEXT_BUTTON = 'buttonNext';
public readonly ALL_FIELDS = [
this.FIRST_NAME, this.MIDDLE_INITIAL, this.LAST_NAME, this.DOB, this.SUFFIX, this.SSN, this.PRIMARY_PHONE,
this.PRIMARY_PHONE_TYPE, this.SECONDARY_PHONE, this.SECONDARY_PHONE_TYPE, this.EMAIL, this.NEXT_BUTTON];
public readonly COAPP_FIELDS = [ ...this.ALL_FIELDS, this.MARITAL_STATUS, this.CO_APPLICANT_SPOUSE];
public readonly MINIMAL_DATA: TestInputSet = [
{ fieldId: this.FIRST_NAME, fieldValue: 'John', fieldType: TestingInputType.TEXT },
{ fieldId: this.MIDDLE_INITIAL, fieldValue: 'A', fieldType: TestingInputType.TEXT },
{ fieldId: this.LAST_NAME, fieldValue: 'DOE', fieldType: TestingInputType.TEXT },
{ fieldId: this.DOB, fieldValue: '01011999', fieldType: TestingInputType.TEXT },
{ fieldId: this.SSN, fieldValue: '111223333', fieldType: TestingInputType.TEXT },
{ fieldId: this.PRIMARY_PHONE, fieldValue: '8475551234', fieldType: TestingInputType.TEXT },
{ fieldId: this.EMAIL, fieldValue: PageDataTools.createRandomEmail(), fieldType: TestingInputType.TEXT },
{ fieldId: this.MARITAL_STATUS, fieldValue: 1, fieldType: TestingInputType.RADIO }
];
public readonly MINIMAL_DATA_NO_MARITAL: TestInputSet = [
{ fieldId: this.FIRST_NAME, fieldValue: 'John', fieldType: TestingInputType.TEXT },
{ fieldId: this.MIDDLE_INITIAL, fieldValue: 'A', fieldType: TestingInputType.TEXT },
{ fieldId: this.LAST_NAME, fieldValue: 'DOE', fieldType: TestingInputType.TEXT },
{ fieldId: this.DOB, fieldValue: '01011999', fieldType: TestingInputType.TEXT },
{ fieldId: this.SSN, fieldValue: '111223333', fieldType: TestingInputType.TEXT },
{ fieldId: this.PRIMARY_PHONE, fieldValue: '8475551234', fieldType: TestingInputType.TEXT },
{ fieldId: this.EMAIL, fieldValue: PageDataTools.createRandomEmail(), fieldType: TestingInputType.TEXT }
];
public readonly MAXIMUM_DATA: TestInputSet = [
...this.MINIMAL_DATA,
{ fieldId: this.SUFFIX, fieldValue: 2, fieldType: TestingInputType.SELECT },
{ fieldId: this.PRIMARY_PHONE_TYPE, fieldValue: 1, fieldType: TestingInputType.RADIO },
{ fieldId: this.SECONDARY_PHONE, fieldValue: '8475561234', fieldType: TestingInputType.TEXT },
{ fieldId: this.SECONDARY_PHONE_TYPE, fieldValue: 0, fieldType: TestingInputType.RADIO }
];
public readonly MAXIMUM_COAPP_DATA: TestInputSet = [
{ fieldId: this.FIRST_NAME, fieldValue: 'Jane', fieldType: TestingInputType.TEXT },
{ fieldId: this.MIDDLE_INITIAL, fieldValue: 'B', fieldType: TestingInputType.TEXT },
{ fieldId: this.LAST_NAME, fieldValue: 'DOE', fieldType: TestingInputType.TEXT },
{ fieldId: this.DOB, fieldValue: '02021998', fieldType: TestingInputType.TEXT },
{ fieldId: this.SUFFIX, fieldValue: 2, fieldType: TestingInputType.SELECT },
{ fieldId: this.SSN, fieldValue: '333223333', fieldType: TestingInputType.TEXT },
{ fieldId: this.PRIMARY_PHONE, fieldValue: '8475554321', fieldType: TestingInputType.TEXT },
{ fieldId: this.EMAIL, fieldValue: PageDataTools.createRandomEmail(), fieldType: TestingInputType.TEXT },
{ fieldId: this.PRIMARY_PHONE_TYPE, fieldValue: 1, fieldType: TestingInputType.RADIO },
{ fieldId: this.SECONDARY_PHONE, fieldValue: '8475564321', fieldType: TestingInputType.TEXT },
{ fieldId: this.SECONDARY_PHONE_TYPE, fieldValue: 0, fieldType: TestingInputType.RADIO },
{ fieldId: this.MARITAL_STATUS, fieldValue: 0, fieldType: TestingInputType.RADIO }
];
public readonly MAXIMUM_COAPP_DATA_PRIMARY: TestInputSet = [
...this.MAXIMUM_COAPP_DATA,
{ fieldId: this.CO_APPLICANT_SPOUSE, fieldValue: 0, fieldType: TestingInputType.RADIO }
];
public readonly MAXIMUM_PRIMARY_NOT_MARRIED_TO_COAPP: TestInputSet = [
...this.MAXIMUM_COAPP_DATA,
{ fieldId: this.CO_APPLICANT_SPOUSE, fieldValue: 1, fieldType: TestingInputType.RADIO }
];
public canGoNext(): promise.Promise<boolean> {
const nextButton = element(by.id(this.NEXT_BUTTON));
if (nextButton) {
return nextButton.isEnabled();
}
throw new Error('Couldn\'t get next button');
}
public submit(): void {
const nextButton = element(by.id(this.NEXT_BUTTON));
nextButton.click();
}
public fillFieldsMinimal(): void {
PageObjectTools.fillFields(this.MINIMAL_DATA);
}
public fillFieldsMinimalNoMarital(): void {
PageObjectTools.fillFields(this.MINIMAL_DATA_NO_MARITAL);
}
public fillFieldsMaximum(): void {
PageObjectTools.fillFields(this.MAXIMUM_DATA);
}
public fillFieldsMaximumCoApplicant(): void {
PageObjectTools.fillFields(this.MAXIMUM_COAPP_DATA_PRIMARY);
}
public fillFieldsMaximumCoApplicantNonPrimary(): void {
PageObjectTools.fillFields(this.MAXIMUM_COAPP_DATA);
}
public fillFieldsPrimaryMarriedButNotMarriedToCoApplicant(): void {
PageObjectTools.fillFields(this.MAXIMUM_PRIMARY_NOT_MARRIED_TO_COAPP);
}
public getFocusedElement() {
return PageObjectTools.getFocusedElement();
}
public getFirstElement(prefix?: string) {
return PageObjectTools.getElementsIdField(this.FIRST_NAME, prefix);
}
}
@@ -0,0 +1,137 @@
import { browser, by, element, ElementFinder, protractor, promise } from 'protractor';
import { PageObjectTools } from '../page-object-tools';
import { TestingInputType, TestInputSet } from '../data-driven/test-input-command';
export class EmploymentPagePo {
public readonly DEFAULT_PREFIX = '';
public readonly PRIOR0_PREFIX = 'priorEmployer0-';
public readonly EMPLOYMENT_INDICATED = 'hasEmploymentIncome0';
public readonly OTHER_INCOME_INDICATED = 'hasOtherIncome0';
public readonly IS_PAYING_CHILD_SUPPORT = 'isPayingChildSupport';
public readonly EMPLOYER_NAME = 'inputEmployerName';
public readonly JOB_TITLE = 'inputJobTitle';
public readonly SALARY = 'inputSalary';
public readonly OTHER_INCOME = 'inputOtherAnnualIncome';
public readonly OTHER_INCOME_SOURCE = 'inputOtherAnnualIncomeSource';
public readonly WORK_PHONE = 'inputWorkPhoneNumber';
public readonly EMPLOYMENT_TYPE = 'inputEmploymentType';
public readonly SCHEDULE = 'inputSchedule';
public readonly EMPLOYMENT_LENGTH_YEARS = 'inputEmploymentLengthYears';
public readonly EMPLOYMENT_LENGTH_MONTHS = 'inputEmploymentLengthMonths';
public readonly CHILD_SUPPORT_AMOUNT = 'inputChildSupportAmount';
public readonly WEEKLY_HOURS = 'inputWeeklyHours';
public readonly NEXT_BUTTON = 'buttonNext';
public readonly STARTING_FIELDS = [this.EMPLOYMENT_INDICATED, this.OTHER_INCOME_INDICATED, this.IS_PAYING_CHILD_SUPPORT];
public readonly EMPLOYMENT_FIELDS = [
this.EMPLOYER_NAME, this.JOB_TITLE, this.SALARY, this.WORK_PHONE, this.EMPLOYMENT_TYPE, this.SCHEDULE,
this.EMPLOYMENT_LENGTH_YEARS, this.EMPLOYMENT_LENGTH_MONTHS];
public readonly MINIMAL_DATA: TestInputSet = [
{ fieldId: this.EMPLOYER_NAME, fieldValue: 'Acme Packaging', fieldType: TestingInputType.TEXT },
{ fieldId: this.JOB_TITLE, fieldValue: 'Acme Packer', fieldType: TestingInputType.TEXT },
{ fieldId: this.SALARY, fieldValue: 30000, fieldType: TestingInputType.TEXT },
{ fieldId: this.EMPLOYMENT_TYPE, fieldValue: 1, fieldType: TestingInputType.SELECT },
{ fieldId: this.SCHEDULE, fieldValue: 1, fieldType: TestingInputType.RADIO },
{ fieldId: this.EMPLOYMENT_LENGTH_YEARS, fieldValue: 3, fieldType: TestingInputType.SELECT },
{ fieldId: this.EMPLOYMENT_LENGTH_MONTHS, fieldValue: 2, fieldType: TestingInputType.SELECT }
];
public readonly SECOND_INCOME_DATA: TestInputSet = [
{ fieldId: this.EMPLOYER_NAME, fieldValue: 'Acme Delivery', fieldType: TestingInputType.TEXT },
{ fieldId: this.JOB_TITLE, fieldValue: 'Delivery Driver', fieldType: TestingInputType.TEXT },
{ fieldId: this.SALARY, fieldValue: 15, fieldType: TestingInputType.TEXT },
{ fieldId: this.EMPLOYMENT_TYPE, fieldValue: 1, fieldType: TestingInputType.SELECT },
{ fieldId: this.SCHEDULE, fieldValue: 1, fieldType: TestingInputType.RADIO },
{ fieldId: this.EMPLOYMENT_LENGTH_YEARS, fieldValue: 3, fieldType: TestingInputType.SELECT },
{ fieldId: this.EMPLOYMENT_LENGTH_MONTHS, fieldValue: 2, fieldType: TestingInputType.SELECT }
];
public readonly MAXIMUM_DATA: TestInputSet = [
...this.MINIMAL_DATA,
{ fieldId: this.WORK_PHONE, fieldValue: 4148765309, fieldType: TestingInputType.TEXT },
];
public readonly OTHER_INCOME_DATA: TestInputSet = [
{ fieldId: this.OTHER_INCOME, fieldValue: 20000, fieldType: TestingInputType.TEXT },
{ fieldId: this.OTHER_INCOME_SOURCE, fieldValue: 'Stuff1', fieldType: TestingInputType.TEXT }
];
public readonly CHILD_SUPPORT_DATA: TestInputSet = [
{ fieldId: this.CHILD_SUPPORT_AMOUNT, fieldValue: 200, fieldType: TestingInputType.TEXT }
];
// Page hides everything by default
public showEmploymentFields(): void {
const showEmployment = element(by.id(this.EMPLOYMENT_INDICATED));
PageObjectTools.clickCheckBox(showEmployment);
}
public showOtherIncomeFields(): void {
const showOtherIncomeOne = element(by.id(this.OTHER_INCOME_INDICATED));
PageObjectTools.clickCheckBox(showOtherIncomeOne);
}
public toggleOtherIncomeGroupOne(): void {
const showOtherIncomeOne = element(by.id(this.OTHER_INCOME_INDICATED));
PageObjectTools.clickCheckBox(showOtherIncomeOne);
}
public clearOtherIncomeGroupOne(): void {
const clearOtherIncomeOneSource = element(by.id(this.OTHER_INCOME_SOURCE));
const clearOtherIncomeOne = element(by.id(this.OTHER_INCOME));
clearOtherIncomeOneSource.clear();
clearOtherIncomeOne.clear();
}
public showChildSupportFields(): void {
const showChildSupport = element(by.id(this.IS_PAYING_CHILD_SUPPORT));
PageObjectTools.clickCheckBox(showChildSupport);
}
public canGoNext(): promise.Promise<boolean> {
const nextButton = element(by.id(this.NEXT_BUTTON));
if (nextButton) {
return nextButton.isEnabled();
}
throw new Error('Couldn\'t get next button');
}
public submit(): void {
const nextButton = element(by.id(this.NEXT_BUTTON));
nextButton.click();
}
public fillFieldsMinimal(): void {
PageObjectTools.fillFields(this.MINIMAL_DATA, this.DEFAULT_PREFIX);
}
public fillFieldsMaximum(): void {
PageObjectTools.fillFields(this.MAXIMUM_DATA, this.DEFAULT_PREFIX);
}
public fillChildSupportFields(): void {
PageObjectTools.fillFields(this.CHILD_SUPPORT_DATA);
}
public fillOtherIncomeFields(): void {
PageObjectTools.fillFields(this.OTHER_INCOME_DATA);
}
/**
* Please note, this may need to be adjusted to match the current required employment length.
* As of 09/14/18, this isn't called...
*/
public markSingleIncomeNotEnough(): void {
PageObjectTools.executeTestInputCommand(
{ fieldId: this.EMPLOYMENT_LENGTH_YEARS, fieldValue: 1, fieldType: TestingInputType.SELECT }, this.DEFAULT_PREFIX);
}
public fillSecondIncome(): void {
PageObjectTools.fillFields(this.SECOND_INCOME_DATA, this.PRIOR0_PREFIX);
}
}
@@ -0,0 +1,122 @@
import { by, element, promise } from 'protractor';
import { PageObjectTools } from '../page-object-tools';
import { TestInputSet, TestingInputType } from '../data-driven/test-input-command';
export class HmdaPagePo {
public readonly DEFAULT_PREFIX = 'applicant-';
// race information
public readonly AMERICAN_INDIAN_ALASKA_NATIVE = 'inputAmericanIndianAlaskaNative';
public readonly AMERICAN_INDIAN_ALASKA_NATIVE_TEXT = 'inputAmericanIndianAlaskaNativeText';
public readonly BLACK_OR_AFRICAN_AMERICAN = 'inputBlackOrAfricanAmerican';
public readonly ASIAN = 'inputAsian';
public readonly ASIAN_INDIAN = 'inputAsianIndian';
public readonly CHINESE = 'inputChinese';
public readonly FILIPINO = 'inputFilipino';
public readonly JAPANESE = 'inputJapanese';
public readonly KOREAN = 'inputKorean';
public readonly VIETNAMESE = 'inputVietnamese';
public readonly OTHER_ASIAN = 'inputOtherAsian';
public readonly OTHER_ASIAN_TEXT = 'inputOtherAsianText';
public readonly HAWAIIAN = 'inputHawaiian';
public readonly NATIVE_HAWAIIAN = 'inputNativeHawaiian';
public readonly GUAMANIAN_CHAMORRO = 'inputNativeGuamanianChamorro';
public readonly SAMOAN = 'inputNativeSamoan';
public readonly OTHER_PACIFIC_ISLANDER = 'inputOtherPacificIslander';
public readonly OTHER_PACIFIC_ISLANDER_TEXT = 'inputOtherPacificIslanderText';
public readonly WHITE = 'inputWhite';
public readonly RACE_DID_NOT_PROVIDE = 'inputRaceDidNotProvide';
// ethnicity information
public readonly HISPANIC_OR_LATINO = 'inputHispanicOrLatino';
public readonly MEXICAN = 'inputMexican';
public readonly PUERTO_RICAN = 'inputPuertoRican';
public readonly CUBAN = 'inputCuban';
public readonly OTHER_HISPANIC_LATINO = 'inputOtherHispanicLatino';
public readonly OTHER_HISPANIC_LATINO_TEXT = 'inputOtherHispanicLatinoText';
public readonly NOT_HISPANIC_OR_LATINO = 'inputNotHispanicOrLatino';
public readonly ETHNICITY_DID_NOT_PROVIDE = 'inputEthnicityDidNotProvide';
// gender information
public readonly FEMALE = 'inputFemale';
public readonly MALE = 'inputMale';
public readonly GENDER_DID_NOT_PROVIDE = 'inputGenderDidNotProvide';
public readonly NEXT_BUTTON = 'buttonNext';
public readonly GENDER_FIELDS = [
this.MALE, this.FEMALE, this.GENDER_DID_NOT_PROVIDE
];
public readonly RACE_FIELDS = [
this.AMERICAN_INDIAN_ALASKA_NATIVE, this.AMERICAN_INDIAN_ALASKA_NATIVE_TEXT, this.BLACK_OR_AFRICAN_AMERICAN, this.ASIAN,
this.ASIAN_INDIAN, this.CHINESE, this.FILIPINO, this.JAPANESE, this.KOREAN, this.VIETNAMESE, this.OTHER_ASIAN, this.OTHER_ASIAN_TEXT,
this.HAWAIIAN, this.NATIVE_HAWAIIAN, this.GUAMANIAN_CHAMORRO, this.SAMOAN, this.OTHER_PACIFIC_ISLANDER,
this.WHITE, this.RACE_DID_NOT_PROVIDE
];
public readonly ETHNICITY_FIELDS = [
this.HISPANIC_OR_LATINO, this.MEXICAN, this.PUERTO_RICAN, this.CUBAN, this.OTHER_HISPANIC_LATINO,
this.OTHER_HISPANIC_LATINO_TEXT, this.NOT_HISPANIC_OR_LATINO, this.ETHNICITY_DID_NOT_PROVIDE,
];
public readonly ALL_FIELDS = [
...this.RACE_FIELDS, ...this.GENDER_FIELDS, ...this.ETHNICITY_FIELDS, this.NEXT_BUTTON
];
public readonly MINIMAL_DATA: TestInputSet = [
{ fieldId: this.RACE_DID_NOT_PROVIDE, fieldValue: 1, fieldType: TestingInputType.CHECK },
{ fieldId: this.ETHNICITY_DID_NOT_PROVIDE, fieldValue: 1, fieldType: TestingInputType.CHECK },
{ fieldId: this.GENDER_DID_NOT_PROVIDE, fieldValue: 1, fieldType: TestingInputType.CHECK }
];
public readonly MAXIMUM_DATA: TestInputSet = [
...this.MINIMAL_DATA,
{ fieldId: this.AMERICAN_INDIAN_ALASKA_NATIVE, fieldValue: 1, fieldType: TestingInputType.CHECK },
{ fieldId: this.AMERICAN_INDIAN_ALASKA_NATIVE_TEXT, fieldValue: 'Enrolled principal or tribe', fieldType: TestingInputType.TEXT },
{ fieldId: this.BLACK_OR_AFRICAN_AMERICAN, fieldValue: 1, fieldType: TestingInputType.CHECK },
{ fieldId: this.ASIAN, fieldValue: 1, fieldType: TestingInputType.CHECK },
{ fieldId: this.ASIAN_INDIAN, fieldValue: 1, fieldType: TestingInputType.CHECK },
{ fieldId: this.CHINESE, fieldValue: 1, fieldType: TestingInputType.CHECK },
{ fieldId: this.FILIPINO, fieldValue: 1, fieldType: TestingInputType.CHECK },
{ fieldId: this.JAPANESE, fieldValue: 1, fieldType: TestingInputType.CHECK },
{ fieldId: this.KOREAN, fieldValue: 1, fieldType: TestingInputType.CHECK },
{ fieldId: this.VIETNAMESE, fieldValue: 1, fieldType: TestingInputType.CHECK },
{ fieldId: this.OTHER_ASIAN, fieldValue: 1, fieldType: TestingInputType.CHECK },
{ fieldId: this.OTHER_ASIAN_TEXT, fieldValue: 'Hmong, Laotian, Thai,Pakistani, Cambodian', fieldType: TestingInputType.TEXT },
{ fieldId: this.HAWAIIAN, fieldValue: 1, fieldType: TestingInputType.CHECK },
{ fieldId: this.NATIVE_HAWAIIAN, fieldValue: 1, fieldType: TestingInputType.CHECK },
{ fieldId: this.GUAMANIAN_CHAMORRO, fieldValue: 1, fieldType: TestingInputType.CHECK },
{ fieldId: this.SAMOAN, fieldValue: 1, fieldType: TestingInputType.CHECK },
{ fieldId: this.OTHER_PACIFIC_ISLANDER, fieldValue: 1, fieldType: TestingInputType.CHECK },
{ fieldId: this.OTHER_PACIFIC_ISLANDER_TEXT, fieldValue: 'Fijian, Tongan', fieldType: TestingInputType.TEXT },
{ fieldId: this.WHITE, fieldValue: 1, fieldType: TestingInputType.CHECK },
{ fieldId: this.HISPANIC_OR_LATINO, fieldValue: 1, fieldType: TestingInputType.CHECK },
{ fieldId: this.MEXICAN, fieldValue: 1, fieldType: TestingInputType.CHECK },
{ fieldId: this.PUERTO_RICAN, fieldValue: 1, fieldType: TestingInputType.CHECK },
{ fieldId: this.CUBAN, fieldValue: 1, fieldType: TestingInputType.CHECK },
{ fieldId: this.OTHER_HISPANIC_LATINO, fieldValue: 1, fieldType: TestingInputType.CHECK },
{ fieldId: this.OTHER_HISPANIC_LATINO_TEXT, fieldValue: 'Argentinean,Colombian, Dominican', fieldType: TestingInputType.TEXT },
{ fieldId: this.NOT_HISPANIC_OR_LATINO, fieldValue: 1, fieldType: TestingInputType.CHECK },
{ fieldId: this.MALE, fieldValue: 1, fieldType: TestingInputType.CHECK },
];
public canGoNext(): promise.Promise<boolean> {
const nextButton = element(by.id(this.NEXT_BUTTON));
if (nextButton) {
return nextButton.isEnabled();
}
throw new Error('Couldn\'t get next button');
}
public submit(): void {
const nextButton = element(by.id(this.NEXT_BUTTON));
nextButton.click();
}
public fillFieldsMinimal(): void {
PageObjectTools.fillFields(this.MINIMAL_DATA , this.DEFAULT_PREFIX);
}
public fillFieldsMaximum(): void {
PageObjectTools.fillFields(this.MAXIMUM_DATA , this.DEFAULT_PREFIX);
}
}
@@ -0,0 +1,143 @@
import { browser, by, element, ElementFinder, protractor, promise } from 'protractor';
import { PageObjectTools } from '../page-object-tools';
import { TestingInputType, TestInputSet } from '../data-driven/test-input-command';
export class ResidencePagePo {
public readonly DEFAULT_PREFIX = 'addressInfo-';
public readonly MAILING_PREFIX = 'mailingInfo-';
public readonly PRIOR_PREFIX = '0-';
public readonly COAPP_PREFIX = '-';
public readonly ADDRESS_LINE_1 = 'inputAddress1';
public readonly ADDRESS_LINE_2 = 'inputAddress2';
public readonly CITY = 'inputCity';
public readonly STATE = 'inputState';
public readonly ZIP = 'inputZip';
public readonly RESIDENCE_STATUS = 'inputResidenceStatus';
public readonly RESIDENCE_MONTHLY_PAYMENT = 'inputResidenceMonthlyPayment';
public readonly RESIDENCE_TIME_YEARS = 'inputResidenceTimeYears';
public readonly RESIDENCE_TIME_MONTHS = 'inputResidenceTimeMonths';
public readonly MAILING_SAME = 'isMailingSameYes';
public readonly IS_ADDRESS_SAME = 'isAddressSame';
public readonly NEXT_BUTTON = 'buttonNext';
public readonly ALL_FIELDS = [
this.ADDRESS_LINE_1, this.ADDRESS_LINE_2, this.CITY, this.STATE, this.ZIP, this.RESIDENCE_STATUS,
this.RESIDENCE_MONTHLY_PAYMENT, this.RESIDENCE_TIME_YEARS, this.RESIDENCE_TIME_MONTHS, this.MAILING_SAME
];
public readonly MAILING_FIELDS = [
this.ADDRESS_LINE_1, this.ADDRESS_LINE_2, this.CITY, this.STATE, this.ZIP
];
public readonly COAPP_FIELDS = [
...this.ALL_FIELDS
];
public readonly MINIMAL_DATA: TestInputSet = [
{ fieldId: this.ADDRESS_LINE_1, fieldValue: '999 South 8th Pl.', fieldType: TestingInputType.TEXT },
{ fieldId: this.CITY, fieldValue: 'Codeville', fieldType: TestingInputType.TEXT },
{ fieldId: this.STATE, fieldValue: 40, fieldType: TestingInputType.SELECT },
{ fieldId: this.ZIP, fieldValue: 53207, fieldType: TestingInputType.TEXT },
{ fieldId: this.RESIDENCE_MONTHLY_PAYMENT, fieldValue: 1500, fieldType: TestingInputType.TEXT },
{ fieldId: this.RESIDENCE_STATUS, fieldValue: 2, fieldType: TestingInputType.SELECT },
{ fieldId: this.RESIDENCE_TIME_YEARS, fieldValue: 4, fieldType: TestingInputType.SELECT },
{ fieldId: this.RESIDENCE_TIME_MONTHS, fieldValue: 4, fieldType: TestingInputType.SELECT }
];
public readonly MINIMAL_DATA_IN_WI: TestInputSet = [
{ fieldId: this.ADDRESS_LINE_1, fieldValue: '999 South 8th Pl.', fieldType: TestingInputType.TEXT },
{ fieldId: this.CITY, fieldValue: 'Codeville', fieldType: TestingInputType.TEXT },
{ fieldId: this.ZIP, fieldValue: 53207, fieldType: TestingInputType.TEXT },
{ fieldId: this.RESIDENCE_MONTHLY_PAYMENT, fieldValue: 1500, fieldType: TestingInputType.TEXT },
{ fieldId: this.RESIDENCE_STATUS, fieldValue: 2, fieldType: TestingInputType.SELECT },
{ fieldId: this.RESIDENCE_TIME_YEARS, fieldValue: 4, fieldType: TestingInputType.SELECT },
{ fieldId: this.RESIDENCE_TIME_MONTHS, fieldValue: 4, fieldType: TestingInputType.SELECT }
];
public readonly MAXIMUM_DATA: TestInputSet = [
{ fieldId: this.ADDRESS_LINE_1, fieldValue: '1000 South 8th Pl.', fieldType: TestingInputType.TEXT },
{ fieldId: this.CITY, fieldValue: 'Codeville', fieldType: TestingInputType.TEXT },
{ fieldId: this.STATE, fieldValue: 40, fieldType: TestingInputType.SELECT },
{ fieldId: this.ZIP, fieldValue: 53207, fieldType: TestingInputType.TEXT },
{ fieldId: this.RESIDENCE_MONTHLY_PAYMENT, fieldValue: 1500, fieldType: TestingInputType.TEXT },
{ fieldId: this.RESIDENCE_STATUS, fieldValue: 2, fieldType: TestingInputType.SELECT },
{ fieldId: this.RESIDENCE_TIME_YEARS, fieldValue: 2, fieldType: TestingInputType.SELECT },
{ fieldId: this.RESIDENCE_TIME_MONTHS, fieldValue: 2, fieldType: TestingInputType.SELECT }
];
public readonly MAILING_DATA: TestInputSet = [
{ fieldId: this.ADDRESS_LINE_1, fieldValue: '111 North 7th St.', fieldType: TestingInputType.TEXT },
{ fieldId: this.CITY, fieldValue: 'Codeville', fieldType: TestingInputType.TEXT },
{ fieldId: this.STATE, fieldValue: 40, fieldType: TestingInputType.SELECT },
{ fieldId: this.ZIP, fieldValue: 53215, fieldType: TestingInputType.TEXT }
];
public readonly PRIOR_RESIDENCE_DATA: TestInputSet = [
{ fieldId: this.ADDRESS_LINE_1, fieldValue: '1000 South 8th Pl.', fieldType: TestingInputType.TEXT },
{ fieldId: this.CITY, fieldValue: 'Codeville', fieldType: TestingInputType.TEXT },
{ fieldId: this.STATE, fieldValue: 40, fieldType: TestingInputType.SELECT },
{ fieldId: this.ZIP, fieldValue: 53207, fieldType: TestingInputType.TEXT },
{ fieldId: this.RESIDENCE_STATUS, fieldValue: 2, fieldType: TestingInputType.SELECT },
{ fieldId: this.RESIDENCE_TIME_YEARS, fieldValue: 2, fieldType: TestingInputType.SELECT },
{ fieldId: this.RESIDENCE_TIME_MONTHS, fieldValue: 2, fieldType: TestingInputType.SELECT }
];
public canGoNext(): promise.Promise<boolean> {
const nextButton = element(by.id(this.NEXT_BUTTON));
if (nextButton) {
return nextButton.isEnabled();
}
throw new Error('Couldn\'t get next button');
}
public submit(): void {
const nextButton = element(by.id(this.NEXT_BUTTON));
nextButton.click();
}
public fillFieldsMinimal(): void {
PageObjectTools.fillFields(this.MINIMAL_DATA, this.DEFAULT_PREFIX);
}
public showMailingAddress(): void {
const mailingIsSameCheck = element(by.id(this.DEFAULT_PREFIX + this.MAILING_SAME));
PageObjectTools.clickCheckBox(mailingIsSameCheck);
}
public showSecondAddress(): void {
PageObjectTools.executeTestInputCommand(
{ fieldId: this.RESIDENCE_TIME_YEARS, fieldValue: 2, fieldType: TestingInputType.SELECT }, this.DEFAULT_PREFIX);
}
public markAddressNotSame(): void {
PageObjectTools.executeTestInputCommand(
{ fieldId: this.IS_ADDRESS_SAME, fieldValue: 1, fieldType: TestingInputType.RADIO });
}
public markAddressSame(): void {
PageObjectTools.executeTestInputCommand(
{ fieldId: this.IS_ADDRESS_SAME, fieldValue: 0, fieldType: TestingInputType.RADIO });
}
public fillFieldsCoApplicant(): void {
PageObjectTools.fillFields(this.MAILING_DATA, this.COAPP_PREFIX);
}
public fillAdditionalFieldsMaximum(): void {
PageObjectTools.fillFields(this.PRIOR_RESIDENCE_DATA, this.PRIOR_PREFIX);
PageObjectTools.fillFields(this.MAILING_DATA, this.MAILING_PREFIX);
}
public fillFieldsMinimalLivingInWI(): void {
PageObjectTools.fillFields(this.MINIMAL_DATA_IN_WI, this.DEFAULT_PREFIX);
}
public getFocusedElement() {
return PageObjectTools.getFocusedElement();
}
public getFirstElement(prefix?: string) {
return PageObjectTools.getElementsIdField(this.ADDRESS_LINE_1, prefix);
}
}
@@ -0,0 +1,41 @@
import { by, element, promise } from 'protractor';
import { PageObjectTools } from '../page-object-tools';
import { TestingInputType, TestInputSet } from '../data-driven/test-input-command';
export class SpouseTypePagePo {
public readonly IS_FULL_INFO_SPOUSE = 'inputIsFullInfoSpouse';
public readonly NEXT_BUTTON = 'buttonNext';
public readonly STARTING_FIELDS = [this.IS_FULL_INFO_SPOUSE];
public readonly FULL_INFO_SPOUSE_DATA: TestInputSet = [
{ fieldId: this.IS_FULL_INFO_SPOUSE, fieldValue: 0, fieldType: TestingInputType.RADIO }
];
public readonly TATTLE_SPOUSE_DATA: TestInputSet = [
{ fieldId: this.IS_FULL_INFO_SPOUSE, fieldValue: 1, fieldType: TestingInputType.RADIO }
];
public canGoNext(): promise.Promise<boolean> {
const nextButton = element(by.id(this.NEXT_BUTTON));
if (nextButton) {
return nextButton.isEnabled();
}
throw new Error('Couldn\'t get next button');
}
public submit(): void {
const nextButton = element(by.id(this.NEXT_BUTTON));
nextButton.click();
}
public fillFieldsFullInfoSpouse(): void {
PageObjectTools.fillFields(this.FULL_INFO_SPOUSE_DATA);
}
public fillFieldsTattleSpouse(): void {
PageObjectTools.fillFields(this.TATTLE_SPOUSE_DATA);
}
}
@@ -0,0 +1,34 @@
import { browser, by, element, ElementFinder, protractor, promise } from 'protractor';
import { PageObjectTools } from '../page-object-tools';
import { PageDataTools } from '../page-data-tools';
import { TestInputSet, TestingInputType } from '../data-driven/test-input-command';
export class SummaryPagePo {
public readonly NEXT_BUTTON = 'buttonNext';
public readonly NOTE_FIELD = 'inputNote';
public readonly PRIMARY_CONTACT = 'inputContact';
public readonly PROMO_CODE = 'inputPromoCode';
public readonly ALL_FIELDS = [this.NOTE_FIELD, this.NEXT_BUTTON];
public readonly MINIMAL_DATA: TestInputSet = [
{ fieldId: this.PRIMARY_CONTACT, fieldValue: 1, fieldType: TestingInputType.SELECT },
];
public canGoNext(): promise.Promise<boolean> {
const nextButton = element(by.id(this.NEXT_BUTTON));
if (nextButton) {
return nextButton.isEnabled();
}
throw new Error('Couldn\'t get next button');
}
public submit(): void {
const nextButton = element(by.id(this.NEXT_BUTTON));
nextButton.click();
}
public fillFieldsMinimal(): void {
PageObjectTools.fillFields(this.MINIMAL_DATA);
}
}
@@ -0,0 +1,75 @@
import { browser, by, element, ElementFinder, protractor, promise } from 'protractor';
import { PageObjectTools } from '../page-object-tools';
import { TestingInputType, TestInputSet } from '../data-driven/test-input-command';
export class TattleSpousePagePo {
public readonly FIRST_NAME = 'inputFirstName';
public readonly MIDDLE_INITIAL = 'inputMiddleInitial';
public readonly LAST_NAME = 'inputLastName';
public readonly ADDRESS_LINE_1 = 'inputAddress1';
public readonly ADDRESS_LINE_2 = 'inputAddress2';
public readonly CITY = 'inputCity';
public readonly STATE = 'inputState';
public readonly ZIP = 'inputZip';
public readonly IS_ADDRESS_SAME = 'isAddressSame';
public readonly NEXT_BUTTON = 'buttonNext';
public readonly ALL_FIELDS = [
this.ADDRESS_LINE_1, this.ADDRESS_LINE_2, this.CITY, this.STATE, this.ZIP, this.IS_ADDRESS_SAME,
this.FIRST_NAME, this.MIDDLE_INITIAL, this.LAST_NAME
];
public readonly MAILING_FIELDS = [
this.ADDRESS_LINE_1, this.ADDRESS_LINE_2, this.CITY, this.STATE, this.ZIP
];
public readonly MINIMAL_DATA: TestInputSet = [
{ fieldId: this.FIRST_NAME, fieldValue: 'Bob', fieldType: TestingInputType.TEXT },
{ fieldId: this.MIDDLE_INITIAL, fieldValue: 'B', fieldType: TestingInputType.TEXT },
{ fieldId: this.LAST_NAME, fieldValue: 'Uecker', fieldType: TestingInputType.TEXT },
{ fieldId: this.IS_ADDRESS_SAME, fieldValue: 0, fieldType: TestingInputType.RADIO }
];
public readonly MAXIMUM_DATA: TestInputSet = [
{ fieldId: this.FIRST_NAME, fieldValue: 'Bob', fieldType: TestingInputType.TEXT },
{ fieldId: this.MIDDLE_INITIAL, fieldValue: 'B', fieldType: TestingInputType.TEXT },
{ fieldId: this.LAST_NAME, fieldValue: 'Uecker', fieldType: TestingInputType.TEXT },
{ fieldId: this.IS_ADDRESS_SAME, fieldValue: 1, fieldType: TestingInputType.RADIO },
{ fieldId: this.ADDRESS_LINE_1, fieldValue: '1000 South 8th Pl.', fieldType: TestingInputType.TEXT },
{ fieldId: this.CITY, fieldValue: 'Codeville', fieldType: TestingInputType.TEXT },
{ fieldId: this.STATE, fieldValue: 40, fieldType: TestingInputType.SELECT },
{ fieldId: this.ZIP, fieldValue: 53207, fieldType: TestingInputType.TEXT }
];
public canGoNext(): promise.Promise<boolean> {
const nextButton = element(by.id(this.NEXT_BUTTON));
if (nextButton) {
return nextButton.isEnabled();
}
throw new Error('Couldn\'t get next button');
}
public submit(): void {
const nextButton = element(by.id(this.NEXT_BUTTON));
nextButton.click();
}
public fillFieldsMinimal(): void {
PageObjectTools.fillFields(this.MINIMAL_DATA);
}
public fillFieldsMaximum(): void {
PageObjectTools.fillFields(this.MAXIMUM_DATA);
}
public getFocusedElement() {
return PageObjectTools.getFocusedElement();
}
public getFirstElement(prefix?: string) {
return PageObjectTools.getElementsIdField(this.ADDRESS_LINE_1, prefix);
}
}
@@ -0,0 +1,93 @@
import { by, element, promise } from 'protractor';
import { PageObjectTools } from '../page-object-tools';
import { TestInputSet, TestingInputType } from '../data-driven/test-input-command';
export class VehicleCollateralPagePo {
// text input fields
public readonly VALUE = 'inputValue';
public readonly YEAR = 'inputYear';
public readonly MAKE = 'inputMake';
public readonly MODEL = 'inputModel';
public readonly MILEAGE = 'inputMileage';
// drop down menus
public readonly TERM = 'inputTerm';
public readonly CONDITION = 'inputCondition';
public readonly LOAN_PURPOSE = 'inputLoanPurpose';
// radio/pill buttons
public readonly TYPE = 'inputType';
public readonly SELLER = 'inputSeller';
public readonly NEXT_BUTTON = 'buttonNext';
public readonly ALL_FIELDS = [this.VALUE, this.CONDITION, this.YEAR,
this.MAKE, this.MODEL, this.MILEAGE, this.TERM, this.LOAN_PURPOSE, this.TYPE, this.SELLER, this.NEXT_BUTTON];
public readonly MINIMAL_DATA: TestInputSet = [
{ fieldId: this.VALUE, fieldValue: '12345', fieldType: TestingInputType.TEXT },
{ fieldId: this.TYPE, fieldValue: 1, fieldType: TestingInputType.RADIO },
{ fieldId: this.CONDITION, fieldValue: 1, fieldType: TestingInputType.SELECT },
{ fieldId: this.YEAR, fieldValue: '2018', fieldType: TestingInputType.TEXT },
{ fieldId: this.MAKE, fieldValue: 'Subaru', fieldType: TestingInputType.TEXT },
{ fieldId: this.MODEL, fieldValue: 'Outback', fieldType: TestingInputType.TEXT },
{ fieldId: this.MILEAGE, fieldValue: '17320', fieldType: TestingInputType.TEXT },
{ fieldId: this.TERM, fieldValue: 2, fieldType: TestingInputType.SELECT },
{ fieldId: this.LOAN_PURPOSE, fieldValue: 1, fieldType: TestingInputType.SELECT }
];
public readonly VEHICLE_SELLER_INFO: TestInputSet = [
{ fieldId: this.SELLER, fieldValue: 1, fieldType: TestingInputType.RADIO }
];
public readonly MAXIMUM_DATA: TestInputSet = [
{ fieldId: this.VALUE, fieldValue: '12345', fieldType: TestingInputType.TEXT },
{ fieldId: this.TYPE, fieldValue: 1, fieldType: TestingInputType.RADIO },
{ fieldId: this.CONDITION, fieldValue: 1, fieldType: TestingInputType.SELECT },
{ fieldId: this.YEAR, fieldValue: '2018', fieldType: TestingInputType.TEXT },
{ fieldId: this.MAKE, fieldValue: 'Subaru', fieldType: TestingInputType.TEXT },
{ fieldId: this.MODEL, fieldValue: 'Outback', fieldType: TestingInputType.TEXT },
{ fieldId: this.MILEAGE, fieldValue: '17320', fieldType: TestingInputType.TEXT },
{ fieldId: this.TERM, fieldValue: 2, fieldType: TestingInputType.SELECT },
{ fieldId: this.LOAN_PURPOSE, fieldValue: 2, fieldType: TestingInputType.SELECT },
...this.VEHICLE_SELLER_INFO
];
public canGoNext(): promise.Promise<boolean> {
const nextButton = element(by.id(this.NEXT_BUTTON));
if (nextButton) {
return nextButton.isEnabled();
}
throw new Error('Couldn\'t get next button');
}
public canClickDropdown(): promise.Promise<boolean> {
const dropdown = element(by.id(this.TERM));
if (dropdown) {
return dropdown.isEnabled();
}
throw new Error('Couldn\'t click the dropbox');
}
public submit(): void {
const nextButton = element(by.id(this.NEXT_BUTTON));
nextButton.click();
}
public fillFieldsMinimal(): void {
PageObjectTools.fillFields(this.MINIMAL_DATA);
}
public fillFieldsMaximum(): void {
PageObjectTools.fillFields(this.MAXIMUM_DATA);
}
public getFocusedElement() {
return PageObjectTools.getFocusedElement();
}
public getFirstElement() {
return PageObjectTools.getElementsIdField(this.VALUE);
}
}
@@ -0,0 +1,35 @@
import { browser, by, element, ElementFinder, protractor, promise } from 'protractor';
export class WizardPagePo {
public readonly NEXT_BUTTON = 'buttonNext';
public readonly PREVIOUS_BUTTON = 'buttonPrevious';
public readonly ALL_FIELDS = [this.PREVIOUS_BUTTON, this.NEXT_BUTTON];
public canGoNext(): promise.Promise<boolean> {
const nextButton = element(by.id(this.NEXT_BUTTON));
if (nextButton) {
return nextButton.isEnabled();
}
throw new Error('Couldn\'t get next button');
}
public canGoPrevious(): promise.Promise<boolean> {
const previousButton = element(by.id(this.PREVIOUS_BUTTON));
if (previousButton) {
return previousButton.isEnabled();
}
throw new Error('Couldn\'t get previous button');
}
public goNext(): void {
const nextButton = element(by.id(this.NEXT_BUTTON));
nextButton.click();
}
public goPrevious(): void {
const nextButton = element(by.id(this.PREVIOUS_BUTTON));
nextButton.click();
}
}
@@ -0,0 +1,91 @@
import {browser, by, element, ElementFinder, protractor} from 'protractor';
import { MaskingService } from 'src/app/shared/masking/masking.service';
export interface ElementIndexer {
[key: string]: ElementFinder;
}
export class SharedAppPo {
public numbersList = '1234567890';
public alphabetList = 'abcdfghijklmnopqrstuvwxyzABCDFGHIJKLMNOPQRSTUVWXYZ';
public emptyPhone = MaskingService.emptyPhone;
navigateTo() {
return browser.get('/');
}
navigateToSpecific(location: string) {
return browser.get(location);
}
getHeaderBar() {
return element(by.css('lw-navigation'));
}
getInputById(id: string): ElementFinder {
return element(by.id(id));
}
createRandomString(stringLength: number) {
const characters = this.alphabetList;
let result = '';
for (let j = stringLength; j > 0; --j) {
result += characters[Math.floor(Math.random() * characters.length)];
}
return result;
}
createRandomNumber(numberLength: number) {
const numbers = this.numbersList;
let result = '';
for (let j = numberLength; j > 0; --j) {
const nextNum = numbers[Math.floor(Math.random() * numbers.length)];
if (nextNum !== '0') {
result += numbers[Math.floor(Math.random() * numbers.length)];
} else {
j++;
}
}
return result;
}
createRandomEmail(startLength = 10, endLength = 10): string {
const begin = this.createRandomString(startLength);
const end = this.createRandomString(endLength);
const email = [begin, '@', end, '.com'];
return email.join('');
}
getPageTitle() {
return browser.getTitle();
}
// used mainly in demos / development
sleep(time: number) {
browser.sleep(time);
}
makeSSN(inputValue) {
return MaskingService.makeSSN(inputValue);
}
makePhone(inputValue) {
return MaskingService.makePhone(inputValue);
}
makeDOB(inputValue) {
return MaskingService.makeDOB(inputValue);
}
makeNumber(inputValue) {
return MaskingService.makeNumber(inputValue);
}
selectDropDownField(elementFinder: ElementFinder, optionNumber: number) {
const desiredOption = elementFinder.all(by.tagName('option')).get(optionNumber);
const EC = protractor.ExpectedConditions;
browser.wait(EC.visibilityOf(desiredOption), 5000).then(() => {
desiredOption.click();
});
}
}
@@ -0,0 +1,34 @@
import { by, element, promise } from 'protractor';
import { PageObjectTools } from '../../shared/page-object-tools';
export class SignatureDisclosuresPagePo {
public readonly PAGE_URL = '/loan-wizard/sl/pe/disclosures';
public readonly DISCLOSE_TRUTHFUL = 'truthful';
public readonly DISCLOSE_CONTACT = 'contact';
public readonly NEXT_BUTTON = 'buttonNext';
public readonly ALL_FIELDS = [
this.DISCLOSE_TRUTHFUL, this.DISCLOSE_CONTACT,
this.NEXT_BUTTON];
public canGoNext(): promise.Promise<boolean> {
const nextButton = element(by.id(this.NEXT_BUTTON));
if (nextButton) {
return nextButton.isEnabled();
}
throw new Error('Couldn\'t get next button');
}
public submit(): void {
const nextButton = element(by.id(this.NEXT_BUTTON));
nextButton.click();
}
public fillFieldsMinimal(): void {
const truthful = element(by.id(this.DISCLOSE_TRUTHFUL));
PageObjectTools.clickCheckBox(truthful);
}
}
@@ -0,0 +1,92 @@
import { by, element, promise } from 'protractor';
import { PageObjectTools } from '../../shared/page-object-tools';
import { TestInputSet, TestingInputType } from '../../shared/data-driven/test-input-command';
export class SignaturePageOnePo {
public readonly PAGE_URL = '/loan-wizard/sl/pe/step-1';
public readonly LIMIT_REQUESTED = 'inputLimitRequested';
public readonly PURPOSE_OF_LOAN_SIGNATURE = 'inputPurposeOfLoanSignature';
public readonly ANOTHER_PERSON = 'inputApplicantType';
public readonly LIVE_IN_WI = 'inputLivesInMaritalPropertyState';
public readonly JOINT_CREDIT = 'inputConfirmJointCredit';
public readonly SELECT_TERM = 'inputTerm';
public readonly CO_APP_LIVE_IN_WI = 'inputCoAppLivesInMaritalPropertyState';
public readonly NEXT_BUTTON = 'buttonNext';
public readonly MODAL_CLOSE_BUTTON = 'modalCloseButton';
public readonly MODAL_OKAY_BUTTON = 'modalOkayButton';
public readonly ALL_FIELDS = [this.SELECT_TERM, this.LIMIT_REQUESTED, this.ANOTHER_PERSON, this.LIVE_IN_WI, this.NEXT_BUTTON, this.PURPOSE_OF_LOAN_SIGNATURE];
public readonly HIDDEN_FIELDS_1 = [this.JOINT_CREDIT, this.CO_APP_LIVE_IN_WI];
public readonly MINIMAL_DATA: TestInputSet = [
{ fieldId: this.LIMIT_REQUESTED, fieldValue: 1234, fieldType: TestingInputType.TEXT },
{ fieldId: this.PURPOSE_OF_LOAN_SIGNATURE, fieldValue: "Other", fieldType: TestingInputType.TEXT},
{ fieldId: this.ANOTHER_PERSON, fieldValue: 1, fieldType: TestingInputType.RADIO },
{ fieldId: this.LIVE_IN_WI, fieldValue: 1, fieldType: TestingInputType.RADIO },
{ fieldId: this.SELECT_TERM, fieldValue: 1, fieldType: TestingInputType.SELECT }
];
public readonly MAXIMUM_DATA: TestInputSet = [
{ fieldId: this.LIMIT_REQUESTED, fieldValue: 1234, fieldType: TestingInputType.TEXT },
{ fieldId: this.PURPOSE_OF_LOAN_SIGNATURE, fieldValue: "Other", fieldType: TestingInputType.TEXT},
{ fieldId: this.ANOTHER_PERSON, fieldValue: 0, fieldType: TestingInputType.RADIO },
{ fieldId: this.LIVE_IN_WI, fieldValue: 0, fieldType: TestingInputType.RADIO },
{ fieldId: this.JOINT_CREDIT, fieldValue: 0, fieldType: TestingInputType.RADIO },
{ fieldId: this.CO_APP_LIVE_IN_WI, fieldValue: 0, fieldType: TestingInputType.RADIO },
{ fieldId: this.SELECT_TERM, fieldValue: 1, fieldType: TestingInputType.SELECT }
];
public readonly JOINT_CREDIT_DATA: TestInputSet = [
{ fieldId: this.ANOTHER_PERSON, fieldValue: 0, fieldType: TestingInputType.RADIO },
{ fieldId: this.JOINT_CREDIT, fieldValue: 1, fieldType: TestingInputType.RADIO }
];
public canGoNext(): promise.Promise<boolean> {
const nextButton = element(by.id(this.NEXT_BUTTON));
if (nextButton) {
return nextButton.isEnabled();
}
throw new Error('Couldn\'t get next button');
}
public canClickDropdown(): promise.Promise<boolean> {
const dropdown = element(by.id(this.SELECT_TERM));
if (dropdown) {
return dropdown.isEnabled();
}
throw new Error('Couldn\'t click the dropbox');
}
public submit(): void {
const nextButton = element(by.id(this.NEXT_BUTTON));
nextButton.click();
}
public fillFieldsForFailureToConfirmJointCredit(): void {
PageObjectTools.fillFields(this.JOINT_CREDIT_DATA);
}
public dismissModalByOkayButton(): void {
const modalOkayButton = element(by.id(this.MODAL_OKAY_BUTTON));
modalOkayButton.click();
}
public fillFieldsMinimal(): void {
PageObjectTools.fillFields(this.MINIMAL_DATA);
}
public fillFieldsMaximum(): void {
PageObjectTools.fillFields(this.MAXIMUM_DATA);
}
public getFocusedElement() {
return PageObjectTools.getFocusedElement();
}
public getFirstElement() {
return PageObjectTools.getElementsIdField(this.LIMIT_REQUESTED);
}
}
@@ -0,0 +1,156 @@
import { browser } from 'protractor';
import { SignaturePageOnePo } from './pages/page-one.po';
import { ContactPagePo } from '../shared/pages/contact-page.po';
import { PageObjectTools } from '../shared/page-object-tools';
import { ResidencePagePo } from '../shared/pages/residence-page.po';
import { EmploymentPagePo } from '../shared/pages/employment-page.po';
import { SignatureDisclosuresPagePo } from './pages/page-disclosures.po';
import { SummaryPagePo } from '../shared/pages/summary-page.po';
import { SpouseTypePagePo } from '../shared/pages/spouse-type-page.po';
describe('It should create a signature loan application for 4 full info individuals', () => {
it('should accept maximum inputs for page 1 (Member/Loan Type)', () => {
const page = new SignaturePageOnePo();
browser.get(page.PAGE_URL);
browser.sleep(1000);
expect(page.getFocusedElement()).toEqual(page.getFirstElement());
let inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canClickDropdown()).toEqual(false);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMaximum();
inputArray = PageObjectTools.findFieldsInPageByIdArray([...page.ALL_FIELDS, ...page.HIDDEN_FIELDS_1]);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length + page.HIDDEN_FIELDS_1.length);
expect(page.canClickDropdown()).toEqual(true);
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept minimum inputs for page 2.A (Personal Info)', () => {
const page = new ContactPagePo();
expect(page.getFocusedElement()).toEqual(page.getFirstElement());
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsPrimaryMarriedButNotMarriedToCoApplicant();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept minimum inputs for page 3.A (Residence)', () => {
const page = new ResidencePagePo();
expect(page.getFocusedElement()).toEqual(page.getFirstElement(page.DEFAULT_PREFIX));
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMinimalLivingInWI();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept minimum inputs for page 4.A (Employment)', () => {
const page = new EmploymentPagePo();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept FULL INFO SPOUSE input for Applicant spouse type page', () => {
const page = new SpouseTypePagePo();
expect(page.canGoNext()).toEqual(false);
page.fillFieldsFullInfoSpouse();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept minimum inputs for page 2.B (Applicant\'s Spouse Personal Info)', () => {
const page = new ContactPagePo();
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMinimalNoMarital();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept minimum inputs for page 3.B (Applicant\'s Spouse Residence)', () => {
const page = new ResidencePagePo();
page.markAddressSame();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept minimum inputs for page 4.B (Applicant\'s Spouse Employment)', () => {
const page = new EmploymentPagePo();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept maximum inputs for page 2.C (Co-Applicant Personal Info)', () => {
const page = new ContactPagePo();
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMaximumCoApplicantNonPrimary();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept minimum inputs for page 3.C (Co-applicant Residence)', () => {
const page = new ResidencePagePo();
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMinimalLivingInWI();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept minimum inputs for page 4.C (Co-applicant Employment)', () => {
const page = new EmploymentPagePo();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept FULL INFO SPOUSE input for CoApplicant spouse type page', () => {
const page = new SpouseTypePagePo();
expect(page.canGoNext()).toEqual(false);
page.fillFieldsFullInfoSpouse();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept minimum inputs for page 2.D (CoApplicant\'s Spouse Personal Info)', () => {
const page = new ContactPagePo();
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMinimalNoMarital();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept minimum inputs for page 3.D (CoApplicant\'s Spouse Residence)', () => {
const page = new ResidencePagePo();
page.markAddressSame();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept minimum inputs for page 4.D (CoApplicant\'s Spouse Employment)', () => {
const page = new EmploymentPagePo();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should maximum inputs for page 5 (Disclosures)', () => {
const page = new SignatureDisclosuresPagePo();
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMinimal();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should show application information on page 6 (Summary)', () => {
const page = new SummaryPagePo();
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
page.fillFieldsMinimal();
expect(page.canGoNext()).toEqual(true);
});
});
@@ -0,0 +1,127 @@
import { browser } from 'protractor';
import { ContactPagePo } from '../shared/pages/contact-page.po';
import { PageObjectTools } from '../shared/page-object-tools';
import { ResidencePagePo } from '../shared/pages/residence-page.po';
import { EmploymentPagePo } from '../shared/pages/employment-page.po';
import { WizardPagePo } from '../shared/pages/wizard-page.po';
import { SignaturePageOnePo } from './pages/page-one.po';
import { SignatureDisclosuresPagePo } from './pages/page-disclosures.po';
describe('It should allow free navigation of a completed signature loan application', () => {
it('should accept maximum inputs for page 1.', () => {
const page = new SignaturePageOnePo();
browser.get(page.PAGE_URL);
expect(page.canClickDropdown()).toEqual(false);
page.fillFieldsMaximum();
expect(page.canClickDropdown()).toEqual(true);
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept maximum inputs for page 2 (Personal Info)', () => {
const page = new ContactPagePo();
page.fillFieldsMaximumCoApplicant();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept maximum inputs for page 3 (Residence)', () => {
const page = new ResidencePagePo();
page.fillFieldsMinimal();
page.showMailingAddress();
page.showSecondAddress();
page.fillAdditionalFieldsMaximum();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept maximum inputs for page 4 (Employment)', () => {
const page = new EmploymentPagePo();
page.showEmploymentFields();
page.showOtherIncomeFields();
page.showChildSupportFields();
page.fillFieldsMaximum();
expect(page.canGoNext()).toEqual(false);
page.fillChildSupportFields();
page.fillOtherIncomeFields();
page.markSingleIncomeNotEnough();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept maximum inputs for page 2.A (Co-Applicant Personal Info)', () => {
const page = new ContactPagePo();
page.fillFieldsMaximum();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept maximum inputs for page 3.A (Co-applicant Residence)', () => {
const page = new ResidencePagePo();
page.markAddressNotSame();
expect(page.getFocusedElement()).toEqual(page.getFirstElement(page.DEFAULT_PREFIX));
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMinimal();
page.showMailingAddress();
page.showSecondAddress();
page.fillAdditionalFieldsMaximum();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept maximum inputs for page 4.A (Co-applicant Employment)', () => {
const page = new EmploymentPagePo();
let inputArray = PageObjectTools.findFieldsInPageByIdArray(page.STARTING_FIELDS);
expect(inputArray.length).toEqual(page.STARTING_FIELDS.length);
expect(page.canGoNext()).toEqual(true);
page.showEmploymentFields();
inputArray = PageObjectTools.findFieldsInPageByIdArray([...page.EMPLOYMENT_FIELDS], page.DEFAULT_PREFIX);
expect(inputArray.length).toEqual([...page.EMPLOYMENT_FIELDS].length);
expect(page.canGoNext()).toEqual(false);
page.showOtherIncomeFields();
page.showChildSupportFields();
page.fillFieldsMaximum();
expect(page.canGoNext()).toEqual(false);
page.fillChildSupportFields();
page.fillOtherIncomeFields();
page.markSingleIncomeNotEnough();
// Will no longer happen.
// expect(page.canGoNext()).toEqual(false);
// page.fillSecondIncome();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should maximum inputs for page 5 (Disclosures)', () => {
const page = new SignatureDisclosuresPagePo();
page.fillFieldsMinimal();
expect(page.canGoNext()).toEqual(true);
});
it('should jump back to the beginning.', () => {
const urlList = [
'http://localhost:4200/loan-wizard/sl/pe/co-applicant-financial',
'http://localhost:4200/loan-wizard/sl/pe/co-applicant-residential',
'http://localhost:4200/loan-wizard/sl/pe/co-applicant-personal',
'http://localhost:4200/loan-wizard/sl/pe/step-4',
'http://localhost:4200/loan-wizard/sl/pe/step-3',
'http://localhost:4200/loan-wizard/sl/pe/step-2',
'http://localhost:4200/loan-wizard/sl/pe/step-1'
];
const page = new WizardPagePo();
urlList.forEach((eachUrl) => {
expect(page.canGoPrevious()).toEqual(true);
page.goPrevious();
browser.getCurrentUrl().then((newUrl) => {
expect(newUrl).toEqual(eachUrl);
});
expect(page.canGoNext()).toEqual(true);
}, this);
});
});
@@ -0,0 +1,141 @@
import { browser } from 'protractor';
import { SignaturePageOnePo } from './pages/page-one.po';
import { ContactPagePo } from '../shared/pages/contact-page.po';
import { PageObjectTools } from '../shared/page-object-tools';
import { ResidencePagePo } from '../shared/pages/residence-page.po';
import { EmploymentPagePo } from '../shared/pages/employment-page.po';
import { SummaryPagePo } from '../shared/pages/summary-page.po';
import { SignatureDisclosuresPagePo } from './pages/page-disclosures.po';
import { protractor } from 'protractor/built/ptor';
describe('It should create a maximum signature loan application ', () => {
it('should accept maximum inputs for page 1 (Member/Loan Type)', () => {
const page = new SignaturePageOnePo();
browser.get(page.PAGE_URL);
browser.sleep(1000);
expect(page.getFocusedElement()).toEqual(page.getFirstElement());
let inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canClickDropdown()).toEqual(false);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMaximum();
inputArray = PageObjectTools.findFieldsInPageByIdArray([...page.ALL_FIELDS, ...page.HIDDEN_FIELDS_1]);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length + page.HIDDEN_FIELDS_1.length);
expect(page.canClickDropdown()).toEqual(true);
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept maximum inputs for page 2 (Personal Info)', () => {
const page = new ContactPagePo();
expect(page.getFocusedElement()).toEqual(page.getFirstElement());
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMaximumCoApplicant();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept maximum inputs for page 3 (Residence)', () => {
const page = new ResidencePagePo();
expect(page.getFocusedElement()).toEqual(page.getFirstElement(page.DEFAULT_PREFIX));
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMinimal();
page.showMailingAddress();
page.showSecondAddress();
page.fillAdditionalFieldsMaximum();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept maximum inputs for page 4 (Employment)', () => {
const page = new EmploymentPagePo();
let inputArray = PageObjectTools.findFieldsInPageByIdArray(page.STARTING_FIELDS);
expect(inputArray.length).toEqual(page.STARTING_FIELDS.length);
expect(page.canGoNext()).toEqual(true);
page.showEmploymentFields();
inputArray = PageObjectTools.findFieldsInPageByIdArray([...page.EMPLOYMENT_FIELDS], page.DEFAULT_PREFIX);
expect(inputArray.length).toEqual([...page.EMPLOYMENT_FIELDS].length);
expect(page.canGoNext()).toEqual(false);
page.showOtherIncomeFields();
page.showChildSupportFields();
page.fillFieldsMaximum();
expect(page.canGoNext()).toEqual(false);
page.fillChildSupportFields();
page.fillOtherIncomeFields();
page.markSingleIncomeNotEnough();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept maximum inputs for page 2.A (Co-Applicant Personal Info)', () => {
const page = new ContactPagePo();
const EC = protractor.ExpectedConditions;
browser.wait(EC.visibilityOf(page.getFirstElement()), 5000).then(() => {});
expect(page.getFocusedElement()).toEqual(page.getFirstElement());
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.COAPP_FIELDS);
expect(inputArray.length).toEqual(page.COAPP_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMaximumCoApplicantNonPrimary();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept maximum inputs for page 3.A (Co-applicant Residence)', () => {
const page = new ResidencePagePo();
page.markAddressNotSame();
expect(page.getFocusedElement()).toEqual(page.getFirstElement(page.DEFAULT_PREFIX));
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMinimal();
page.showMailingAddress();
page.showSecondAddress();
page.fillAdditionalFieldsMaximum();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept maximum inputs for page 4.A (Co-applicant Employment)', () => {
const page = new EmploymentPagePo();
let inputArray = PageObjectTools.findFieldsInPageByIdArray(page.STARTING_FIELDS);
expect(inputArray.length).toEqual(page.STARTING_FIELDS.length);
expect(page.canGoNext()).toEqual(true);
page.showEmploymentFields();
inputArray = PageObjectTools.findFieldsInPageByIdArray([...page.EMPLOYMENT_FIELDS], page.DEFAULT_PREFIX);
expect(inputArray.length).toEqual([...page.EMPLOYMENT_FIELDS].length);
expect(page.canGoNext()).toEqual(false);
page.showOtherIncomeFields();
page.showChildSupportFields();
page.fillFieldsMaximum();
expect(page.canGoNext()).toEqual(false);
page.fillChildSupportFields();
page.fillOtherIncomeFields();
page.markSingleIncomeNotEnough();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should maximum inputs for page 5 (Disclosures)', () => {
const page = new SignatureDisclosuresPagePo();
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMinimal();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should show application information on page 6 (Summary)', () => {
const page = new SummaryPagePo();
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
page.fillFieldsMinimal();
expect(page.canGoNext()).toEqual(true);
});
});
@@ -0,0 +1,78 @@
import { browser } from 'protractor';
import { ContactPagePo } from '../shared/pages/contact-page.po';
import { PageObjectTools } from '../shared/page-object-tools';
import { ResidencePagePo } from '../shared/pages/residence-page.po';
import { EmploymentPagePo } from '../shared/pages/employment-page.po';
import { SummaryPagePo } from '../shared/pages/summary-page.po';
import { SignaturePageOnePo } from './pages/page-one.po';
import { SignatureDisclosuresPagePo } from './pages/page-disclosures.po';
describe('It should create a minimal signature loan application ', () => {
it('should accept basic inputs for page 1 (Member/Loan Type)', () => {
const page = new SignaturePageOnePo();
browser.get(page.PAGE_URL);
browser.sleep(1000);
expect(page.getFocusedElement()).toEqual(page.getFirstElement());
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
expect(page.canClickDropdown()).toEqual(false);
page.fillFieldsMinimal();
expect(page.canClickDropdown()).toEqual(true);
expect(page.canGoNext()).toEqual(true);
page.fillFieldsForFailureToConfirmJointCredit();
expect(page.canGoNext()).toEqual(false);
page.dismissModalByOkayButton();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept basic inputs for page 2 (Personal Info)', () => {
const page = new ContactPagePo();
expect(page.getFocusedElement()).toEqual(page.getFirstElement());
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMinimal();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept basic inputs for page 3 (Residence)', () => {
const page = new ResidencePagePo();
expect(page.getFocusedElement()).toEqual(page.getFirstElement(page.DEFAULT_PREFIX));
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMinimal();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept basic inputs for page 4 (Employment)', () => {
const page = new EmploymentPagePo();
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.STARTING_FIELDS);
expect(inputArray.length).toEqual(page.STARTING_FIELDS.length);
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept basic inputs for page 5 (Disclosures)', () => {
const page = new SignatureDisclosuresPagePo();
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMinimal();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should show application information on page 6 (Summary)', () => {
const page = new SummaryPagePo();
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
page.fillFieldsMinimal();
expect(page.canGoNext()).toEqual(true);
});
});
@@ -0,0 +1,132 @@
import { browser } from 'protractor';
import { SignaturePageOnePo } from './pages/page-one.po';
import { ContactPagePo } from '../shared/pages/contact-page.po';
import { PageObjectTools } from '../shared/page-object-tools';
import { ResidencePagePo } from '../shared/pages/residence-page.po';
import { EmploymentPagePo } from '../shared/pages/employment-page.po';
import { SignatureDisclosuresPagePo } from './pages/page-disclosures.po';
import { SummaryPagePo } from '../shared/pages/summary-page.po';
import { SpouseTypePagePo } from '../shared/pages/spouse-type-page.po';
import { TattleSpousePagePo } from '../shared/pages/tattle-spouse-page.po';
describe('It should create a signature loan application for 2 full info individuals + 2 tattle spouses', () => {
it('should accept maximum inputs for page 1 (Member/Loan Type)', () => {
const page = new SignaturePageOnePo();
browser.get(page.PAGE_URL);
browser.sleep(1000);
expect(page.getFocusedElement()).toEqual(page.getFirstElement());
let inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canClickDropdown()).toEqual(false);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMaximum();
inputArray = PageObjectTools.findFieldsInPageByIdArray([...page.ALL_FIELDS, ...page.HIDDEN_FIELDS_1]);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length + page.HIDDEN_FIELDS_1.length);
expect(page.canClickDropdown()).toEqual(true);
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept minimum inputs for page 2.A (Personal Info)', () => {
const page = new ContactPagePo();
expect(page.getFocusedElement()).toEqual(page.getFirstElement());
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsPrimaryMarriedButNotMarriedToCoApplicant();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept minimum inputs for page 3.A (Residence)', () => {
const page = new ResidencePagePo();
expect(page.getFocusedElement()).toEqual(page.getFirstElement(page.DEFAULT_PREFIX));
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMinimalLivingInWI();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept minimum inputs for page 4.A (Employment)', () => {
const page = new EmploymentPagePo();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept TATTLE SPOUSE input for Applicant spouse type page', () => {
const page = new SpouseTypePagePo();
expect(page.canGoNext()).toEqual(false);
page.fillFieldsTattleSpouse();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept minimum inputs for tattle spouse page (Applicant\'s Spouse Tattle Info)', () => {
const page = new TattleSpousePagePo();
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMinimal();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept maximum inputs for page 2.C (Co-Applicant Personal Info)', () => {
const page = new ContactPagePo();
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMaximumCoApplicantNonPrimary();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept minimum inputs for page 3.C (Co-applicant Residence)', () => {
const page = new ResidencePagePo();
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMinimalLivingInWI();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept minimum inputs for page 4.C (Co-applicant Employment)', () => {
const page = new EmploymentPagePo();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept TATTLE SPOUSE input for CoApplicant spouse type page', () => {
const page = new SpouseTypePagePo();
expect(page.canGoNext()).toEqual(false);
page.fillFieldsTattleSpouse();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept minimum inputs for tattle spouse page (CoApplicant\'s Spouse Tattle Info)', () => {
const page = new TattleSpousePagePo();
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMinimal();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should maximum inputs for page 5 (Disclosures)', () => {
const page = new SignatureDisclosuresPagePo();
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMinimal();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should show application information on page 6 (Summary)', () => {
const page = new SummaryPagePo();
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
page.fillFieldsMinimal();
expect(page.canGoNext()).toEqual(true);
});
});
@@ -0,0 +1,77 @@
import { browser, by, element, ElementFinder, protractor, promise } from 'protractor';
import { PageObjectTools } from '../../shared/page-object-tools';
import { TestInputSet, TestInputCommand, TestingInputType } from '../../shared/data-driven/test-input-command';
export class VehiclePageOnePo {
public readonly PAGE_URL = '/loan-wizard/ve/auto/step-1';
public readonly LIMIT_REQUESTED = 'inputLimitRequested';
public readonly ANOTHER_PERSON = 'inputApplicantType';
public readonly LIVE_IN_WI = 'inputLivesInMaritalPropertyState';
public readonly JOINT_CREDIT = 'inputConfirmJointCredit';
public readonly CO_APP_LIVE_IN_WI = 'inputCoAppLivesInMaritalPropertyState';
public readonly NEXT_BUTTON = 'buttonNext';
public readonly MODAL_CLOSE_BUTTON = 'modalCloseButton';
public readonly MODAL_OKAY_BUTTON = 'modalOkayButton';
public readonly ALL_FIELDS = [this.LIMIT_REQUESTED, this.ANOTHER_PERSON, this.LIVE_IN_WI, this.NEXT_BUTTON];
public readonly HIDDEN_FIELDS_1 = [this.JOINT_CREDIT, this.CO_APP_LIVE_IN_WI];
public readonly MINIMAL_DATA: TestInputSet = [
{ fieldId: this.LIMIT_REQUESTED, fieldValue: 54321, fieldType: TestingInputType.TEXT },
{ fieldId: this.ANOTHER_PERSON, fieldValue: 1, fieldType: TestingInputType.RADIO },
{ fieldId: this.LIVE_IN_WI, fieldValue: 1, fieldType: TestingInputType.RADIO }
];
public readonly MAXIMUM_DATA: TestInputSet = [
{ fieldId: this.LIMIT_REQUESTED, fieldValue: 54321, fieldType: TestingInputType.TEXT },
{ fieldId: this.ANOTHER_PERSON, fieldValue: 0, fieldType: TestingInputType.RADIO },
{ fieldId: this.LIVE_IN_WI, fieldValue: 0, fieldType: TestingInputType.RADIO },
{ fieldId: this.JOINT_CREDIT, fieldValue: 0, fieldType: TestingInputType.RADIO },
{ fieldId: this.CO_APP_LIVE_IN_WI, fieldValue: 0, fieldType: TestingInputType.RADIO }
];
public readonly JOINT_CREDIT_DATA: TestInputSet = [
{ fieldId: this.ANOTHER_PERSON, fieldValue: 0, fieldType: TestingInputType.RADIO },
{ fieldId: this.JOINT_CREDIT, fieldValue: 1, fieldType: TestingInputType.RADIO }
];
public canGoNext(): promise.Promise<boolean> {
const nextButton = element(by.id(this.NEXT_BUTTON));
if (nextButton) {
return nextButton.isEnabled();
}
throw new Error('Couldn\'t get next button');
}
public submit(): void {
const nextButton = element(by.id(this.NEXT_BUTTON));
nextButton.click();
}
public fillFieldsForFailureToConfirmJointCredit(): void {
PageObjectTools.fillFields(this.JOINT_CREDIT_DATA);
}
public dismissModalByOkayButton(): void {
const modalOkayButton = element(by.id(this.MODAL_OKAY_BUTTON));
modalOkayButton.click();
}
public fillFieldsMinimal(): void {
PageObjectTools.fillFields(this.MINIMAL_DATA);
}
public fillFieldsMaximum(): void {
PageObjectTools.fillFields(this.MAXIMUM_DATA);
}
public getFocusedElement() {
return PageObjectTools.getFocusedElement();
}
public getFirstElement() {
return PageObjectTools.getElementsIdField(this.LIMIT_REQUESTED);
}
}
@@ -0,0 +1,152 @@
import { browser, protractor } from 'protractor';
import { PageObjectTools } from '../shared/page-object-tools';
import { VehiclePageOnePo } from './pages/page-one.po';
import { ContactPagePo } from '../shared/pages/contact-page.po';
import { EmploymentPagePo } from '../shared/pages/employment-page.po';
import { ResidencePagePo } from '../shared/pages/residence-page.po';
import { SummaryPagePo } from '../shared/pages/summary-page.po';
import { CreditCardDisclosuresPagePo } from '../credit-card/pages/page-disclosures.po';
import { VehicleCollateralPagePo } from '../shared/pages/vehicle-collateral-page.po';
describe('It should create a maximum vehicle application ', () => {
it('should accept maximum inputs for page 1 (Member/Loan Type)', () => {
const page = new VehiclePageOnePo();
browser.get(page.PAGE_URL);
browser.sleep(1000);
expect(page.getFocusedElement()).toEqual(page.getFirstElement());
let inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMaximum();
inputArray = PageObjectTools.findFieldsInPageByIdArray([...page.ALL_FIELDS, ...page.HIDDEN_FIELDS_1]);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length + page.HIDDEN_FIELDS_1.length);
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept maximum inputs for page 2 (Personal Info)', () => {
const page = new ContactPagePo();
expect(page.getFocusedElement()).toEqual(page.getFirstElement());
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMaximumCoApplicant();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept maximum inputs for page 3 (Residence)', () => {
const page = new ResidencePagePo();
expect(page.getFocusedElement()).toEqual(page.getFirstElement(page.DEFAULT_PREFIX));
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMinimal();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept maximum inputs for page 4 (Employment)', () => {
const page = new EmploymentPagePo();
let inputArray = PageObjectTools.findFieldsInPageByIdArray(page.STARTING_FIELDS, page.DEFAULT_PREFIX);
expect(inputArray.length).toEqual(page.STARTING_FIELDS.length);
expect(page.canGoNext()).toEqual(true);
page.showEmploymentFields();
inputArray = PageObjectTools.findFieldsInPageByIdArray([...page.STARTING_FIELDS, ...page.EMPLOYMENT_FIELDS], page.DEFAULT_PREFIX);
expect(inputArray.length).toEqual([...page.STARTING_FIELDS, ...page.EMPLOYMENT_FIELDS].length);
expect(page.canGoNext()).toEqual(false);
page.showOtherIncomeFields();
page.showChildSupportFields();
page.fillFieldsMaximum();
expect(page.canGoNext()).toEqual(false);
page.fillChildSupportFields();
page.fillOtherIncomeFields();
page.markSingleIncomeNotEnough();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept maximum inputs for page 2.A (Co-Applicant Personal Info)', () => {
const page = new ContactPagePo();
const EC = protractor.ExpectedConditions;
browser.wait(EC.visibilityOf(page.getFirstElement()), 5000).then(() => {});
expect(page.getFocusedElement()).toEqual(page.getFirstElement());
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.COAPP_FIELDS);
expect(inputArray.length).toEqual(page.COAPP_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMaximumCoApplicantNonPrimary();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept maximum inputs for page 3.A (Co-applicant Residence)', () => {
const page = new ResidencePagePo();
page.markAddressNotSame();
expect(page.getFocusedElement()).toEqual(page.getFirstElement(page.DEFAULT_PREFIX));
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMinimal();
page.showMailingAddress();
page.showSecondAddress();
page.fillAdditionalFieldsMaximum();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept maximum inputs for page 4.A (Co-applicant Employment)', () => {
const page = new EmploymentPagePo();
let inputArray = PageObjectTools.findFieldsInPageByIdArray(page.STARTING_FIELDS);
expect(inputArray.length).toEqual(page.STARTING_FIELDS.length);
expect(page.canGoNext()).toEqual(true);
page.showEmploymentFields();
inputArray = PageObjectTools.findFieldsInPageByIdArray([...page.EMPLOYMENT_FIELDS], page.DEFAULT_PREFIX);
expect(inputArray.length).toEqual([...page.EMPLOYMENT_FIELDS].length);
expect(page.canGoNext()).toEqual(false);
page.showOtherIncomeFields();
page.showChildSupportFields();
page.fillFieldsMaximum();
expect(page.canGoNext()).toEqual(false);
page.fillChildSupportFields();
page.fillOtherIncomeFields();
page.markSingleIncomeNotEnough();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept maximum inputs for page 4.B (Vehicle Collateral)', () => {
const page = new VehicleCollateralPagePo();
const EC = protractor.ExpectedConditions;
browser.wait(EC.visibilityOf(page.getFirstElement()), 5000).then(() => {});
expect(page.getFocusedElement()).toEqual(page.getFirstElement());
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canClickDropdown()).toEqual(false);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMaximum();
expect(page.canClickDropdown()).toEqual(true);
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept maximum inputs for page 5 (Disclosures)', () => {
const page = new CreditCardDisclosuresPagePo();
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMinimal();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should show application information on page 6 (Summary)', () => {
const page = new SummaryPagePo();
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
page.fillFieldsMinimal();
expect(page.canGoNext()).toEqual(true);
});
});
@@ -0,0 +1,96 @@
import { browser } from 'protractor';
import { PageObjectTools } from '../shared/page-object-tools';
import { VehiclePageOnePo } from './pages/page-one.po';
import { ContactPagePo } from '../shared/pages/contact-page.po';
import { EmploymentPagePo } from '../shared/pages/employment-page.po';
import { ResidencePagePo } from '../shared/pages/residence-page.po';
import { SummaryPagePo } from '../shared/pages/summary-page.po';
import { CreditCardDisclosuresPagePo } from '../credit-card/pages/page-disclosures.po';
import { VehicleCollateralPagePo } from '../shared/pages/vehicle-collateral-page.po';
describe('It should create a minimal vehicle application ', () => {
it('should accept basic inputs for page 1 (Member/Loan Type)', () => {
const page = new VehiclePageOnePo();
browser.get(page.PAGE_URL);
browser.sleep(1000);
expect(page.getFocusedElement()).toEqual(page.getFirstElement());
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMinimal();
expect(page.canGoNext()).toEqual(true);
page.fillFieldsForFailureToConfirmJointCredit();
expect(page.canGoNext()).toEqual(false);
page.dismissModalByOkayButton();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept basic inputs for page 2 (Personal Info)', () => {
const page = new ContactPagePo();
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMinimal();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept basic inputs for page 3 (Residence)', () => {
const page = new ResidencePagePo();
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMinimal();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept basic inputs for page 4 (Employment)', () => {
const page = new EmploymentPagePo();
let inputArray = PageObjectTools.findFieldsInPageByIdArray(page.STARTING_FIELDS, page.DEFAULT_PREFIX);
expect(inputArray.length).toEqual(page.STARTING_FIELDS.length);
expect(page.canGoNext()).toEqual(true);
page.showEmploymentFields();
inputArray = PageObjectTools.findFieldsInPageByIdArray([...page.STARTING_FIELDS, ...page.EMPLOYMENT_FIELDS], page.DEFAULT_PREFIX);
expect(inputArray.length).toEqual([...page.STARTING_FIELDS, ...page.EMPLOYMENT_FIELDS].length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMinimal();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept basic inputs for collateral page 4.A (Vehicle Collateral)', () => {
const page = new VehicleCollateralPagePo();
expect(page.getFocusedElement()).toEqual(page.getFirstElement());
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canClickDropdown()).toEqual(false);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMinimal();
expect(page.canClickDropdown()).toEqual(true);
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should accept basic inputs for page 5 (Disclosures)', () => {
const page = new CreditCardDisclosuresPagePo();
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
expect(page.canGoNext()).toEqual(false);
page.fillFieldsMinimal();
expect(page.canGoNext()).toEqual(true);
page.submit();
});
it('should show application information on page 6 (Summary)', () => {
const page = new SummaryPagePo();
const inputArray = PageObjectTools.findFieldsInPageByIdArray(page.ALL_FIELDS);
expect(inputArray.length).toEqual(page.ALL_FIELDS.length);
page.fillFieldsMinimal();
expect(page.canGoNext()).toEqual(true);
});
});
@@ -0,0 +1,13 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/app",
"module": "commonjs",
"target": "es5",
"types": [
"jasmine",
"jasminewd2",
"node"
]
}
}
@@ -0,0 +1,44 @@
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: online-loan-app
spec:
replicas: 1
selector:
matchLabels:
app: online-loan-app
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
labels:
app: online-loan-app
spec:
containers:
- name: online-loan-app
env: []
image: online-loan-app
resources:
limits:
memory: "1536Mi"
requests:
memory: "1536Mi"
cpu: "100m"
ports:
- containerPort: 80
livenessProbe:
initialDelaySeconds: 5
periodSeconds: 5
httpGet:
path: /
port: 80
readinessProbe:
initialDelaySeconds: 5
periodSeconds: 5
httpGet:
path: /
port: 80
@@ -0,0 +1,11 @@
---
apiVersion: v1
kind: Service
metadata:
name: online-loan-app
spec:
selector:
app: online-loan-app
ports:
- port: 80
targetPort: 80
@@ -0,0 +1,8 @@
resources:
- Deployment.yaml
- Service.yaml
- virtual-service.yaml
images:
- name: online-loan-app
newName: landmarkcu/lcu.api.internal.onlineloanapp
@@ -0,0 +1,19 @@
---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: online-loan-app
spec:
hosts: []
gateways:
- istio-system/ingress-gateway
http:
- name: online-loan-app
match:
- uri:
prefix: /
route:
- destination:
host: online-loan-app
port:
number: 80
@@ -0,0 +1,7 @@
resources:
- ../../../base
patchesStrategicMerge:
- set_appsettings_deployment.yaml
images:
- name: online-loan-app
newName: landmarkcu/lcu.api.internal.onlineloanapp-onlineloanapp
@@ -0,0 +1,12 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: online-loan-app
spec:
template:
spec:
containers:
- name: online-loan-app
env:
- name: ASPNETCORE_ENVIRONMENT
value: "Development"
@@ -0,0 +1,2 @@
resources:
- normal
@@ -0,0 +1,17 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: online-loan-app-configmap
data:
primary.json: |
{
"Primary": {
"SeqUrl": "https://qa-seq.lcu-internal.com",
"CorsAllowedOrigins": [
"http://localhost:3000",
"http://lcu-internal.com",
"https://lcu-internal.com",
"https://qa-api.lcu-internal.com"
]
}
}
@@ -0,0 +1,5 @@
resources:
- configmap.yaml
- ../common
patchesStrategicMerge:
- set_virtual_service.yaml
@@ -0,0 +1,8 @@
---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: online-loan-app
spec:
hosts:
- online-loan-app.apps.azure.lcu-internal.com
@@ -0,0 +1,7 @@
resources:
- ../../../base
patchesStrategicMerge:
- set_appsettings_deployment.yaml
images:
- name: online-loan-app
newName: landmarkcu/lcu.api.internal.onlineloanapp-onlineloanapp
@@ -0,0 +1,13 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: online-loan-app
spec:
template:
spec:
containers:
- name: online-loan-app
env:
- name: ASPNETCORE_ENVIRONMENT
value: "Production"
@@ -0,0 +1,2 @@
resources:
- normal
@@ -0,0 +1,16 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: online-loan-app-configmap
data:
primary.json: |
{
"Primary": {
"SeqUrl": "https://seq.lcu-internal.com",
"CorsAllowedOrigins": [
"http://lcu-internal.com",
"https://lcu-internal.com",
"https://api.lcu-internal.com"
]
}
}
@@ -0,0 +1,5 @@
resources:
- configmap.yaml
- ../common
patchesStrategicMerge:
- set_virtual_service.yaml
@@ -0,0 +1,18 @@
---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: online-loan-app
spec:
hosts:
- prd-online-loan-app.apps.azure.lcu-internal.com
http:
- name: online-loan-app
match:
- uri:
prefix: /
route:
- destination:
host: online-loan-app
port:
number: 80
@@ -0,0 +1,7 @@
resources:
- ../../../base
patchesStrategicMerge:
- set_appsettings_deployment.yaml
images:
- name: online-loan-app
newName: landmarkcu/lcu.api.internal.onlineloanapp-onlineloanapp
@@ -0,0 +1,12 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: online-loan-app
spec:
template:
spec:
containers:
- name: online-loan-app
env:
- name: ASPNETCORE_ENVIRONMENT
value: "Development"
@@ -0,0 +1,2 @@
resources:
- normal
@@ -0,0 +1,17 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: online-loan-app-configmap
data:
primary.json: |
{
"Primary": {
"SeqUrl": "https://qa-seq.lcu-internal.com",
"CorsAllowedOrigins": [
"http://localhost:3000",
"http://lcu-internal.com",
"https://lcu-internal.com",
"https://qa-api.lcu-internal.com"
]
}
}
@@ -0,0 +1,5 @@
resources:
- configmap.yaml
- ../common
patchesStrategicMerge:
- set_virtual_service.yaml
@@ -0,0 +1,18 @@
---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: online-loan-app
spec:
hosts:
- qa-online-loan-app.apps.azure.lcu-internal.com
http:
- name: online-loan-app
match:
- uri:
prefix: /
route:
- destination:
host: online-loan-app
port:
number: 80
@@ -0,0 +1,7 @@
resources:
- ../../../base
patchesStrategicMerge:
- set_appsettings_deployment.yaml
images:
- name: online-loan-app
newName: landmarkcu/lcu.api.internal.onlineloanapp-onlineloanapp
@@ -0,0 +1,12 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: online-loan-app
spec:
template:
spec:
containers:
- name: online-loan-app
env:
- name: ASPNETCORE_ENVIRONMENT
value: "Staging"
@@ -0,0 +1,2 @@
resources:
- normal
@@ -0,0 +1,17 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: online-loan-app-configmap
data:
primary.json: |
{
"Primary": {
"SeqUrl": "https://uat-seq.lcu-internal.com",
"CorsAllowedOrigins": [
"http://localhost:3000",
"http://lcu-internal.com",
"https://lcu-internal.com",
"https://uat-api.lcu-internal.com"
]
}
}
@@ -0,0 +1,5 @@
resources:
- configmap.yaml
- ../common
patchesStrategicMerge:
- set_virtual_service.yaml
@@ -0,0 +1,18 @@
---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: online-loan-app
spec:
hosts:
- uat-online-loan-app.apps.azure.lcu-internal.com
http:
- name: online-loan-app
match:
- uri:
prefix: /
route:
- destination:
host: online-loan-app
port:
number: 80
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,106 @@
{
"name": "ui",
"version": "4.11.0",
"scripts": {
"ng": "ng",
"update-e2e": "webdriver-manager update",
"start": "SET NODE_OPTIONS=--openssl-legacy-provider && ng serve --proxy-config proxy.conf.json --configuration=local --ssl",
"build-develop": "SET NODE_OPTIONS=--openssl-legacy-provider && ng build --configuration=dev",
"build-release": "SET NODE_OPTIONS=--openssl-legacy-provider && ng build --configuration=qa",
"build-master": "SET NODE_OPTIONS=--openssl-legacy-provider && ng build --prod --build-optimizer",
"test": "ng test --watch=false --code-coverage --no-progress",
"test-debug": "ng test --watch=false --source-map=false --no-progress",
"test-interactive": "ng test --watch=false --browsers=Chrome --no-progress",
"lint": "ng lint",
"e2e": "ng e2e",
"postinstall": "node version.js",
"commitmsg": "validate-commit-msg",
"release": "standard-version"
},
"private": true,
"dependencies": {
"@angular/animations": "^6.0.3",
"@angular/cdk": "6.4.7",
"@angular/common": "^6.0.3",
"@angular/compiler": "^6.0.3",
"@angular/core": "^6.0.3",
"@angular/forms": "^6.0.3",
"@angular/http": "^6.0.3",
"@angular/material": "6.4.7",
"@angular/platform-browser": "^6.0.3",
"@angular/platform-browser-dynamic": "^6.0.3",
"@angular/router": "^6.0.3",
"@fortawesome/fontawesome": "^1.1.8",
"@fortawesome/fontawesome-free-regular": "^5.0.13",
"@fortawesome/fontawesome-free-solid": "^5.0.13",
"@ng-bootstrap/ng-bootstrap": "^2.1.0",
"@ngx-translate/core": "^10.0.2",
"@ngx-translate/http-loader": "^3.0.1",
"angular2-text-mask": "^9.0.0",
"bootstrap": "^4.1.1",
"core-js": "^2.5.4",
"file-saver": "^2.0.0",
"fs-extra": "^7.0.0",
"git-describe": "^4.0.3",
"microsoft-adal-angular6": "^1.0.0",
"rxjs": "^6.0.0",
"text-mask-addons": "^3.7.2",
"zone.js": "^0.8.26"
},
"devDependencies": {
"@angular-devkit/build-angular": "~0.8.9",
"@angular/cli": "~6.0.8",
"@angular/compiler-cli": "^6.0.3",
"@angular/language-service": "^6.0.3",
"@types/jasmine": "~2.8.6",
"@types/jasminewd2": "~2.0.3",
"@types/node": "~8.9.4",
"codelyzer": "~4.2.1",
"commitizen": "^3.0.4",
"cz-conventional-changelog": "^2.1.0",
"jasmine-core": "~2.99.1",
"jasmine-spec-reporter": "~4.2.1",
"karma": "~1.7.1",
"karma-chrome-launcher": "^2.2.0",
"karma-coverage-istanbul-reporter": "~2.0.0",
"karma-spec-reporter": "^0.0.36",
"karma-edge-launcher": "^0.4.2",
"karma-firefox-launcher": "^1.1.0",
"karma-ie-launcher": "^1.0.0",
"karma-jasmine": "~1.1.1",
"karma-jasmine-html-reporter": "^0.2.2",
"karma-junit-reporter": "^1.2.0",
"ng-bullet": "^1.0.3",
"protractor": "~5.3.0",
"puppeteer": "^1.5.0",
"sass": "^1.49.9",
"standard-version": "^4.4.0",
"ts-node": "~5.0.1",
"tslint": "~5.9.1",
"typescript": "~2.7.2",
"validate-commit-msg": "^2.14.0"
},
"config": {
"commitizen": {
"path": "./node_modules/cz-conventional-changelog"
},
"validate-commit-msg": {
"types": [
"feat",
"fix",
"docs",
"style",
"refactor",
"perf",
"test",
"chore",
"revert"
],
"warnOnFail": false,
"maxSubjectLength": 100,
"subjectPattern": "^.*",
"subjectPatternErrorMsg": "Subject must be in format 'Commit message'",
"helpMessage": ""
}
}
}
@@ -0,0 +1,44 @@
# Landmark Credit Union
# Loan Wizard Environment Setup
# Running this script on a Windows 10 machine should install all of the software you need
# to work on the project for both the client and api.
# You can use 'choco upgrade all' to keep software up to date.
Write-Output "Starting environment setup, if you use Visual Studio, or Webstorm, install those separately"
# 1. Create an update function.
function Update-Environment-Path
{
$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") `
+ ";" + [System.Environment]::GetEnvironmentVariable("Path","User")
}
# 2. Get the Choco package manager, to enable the rest of this script
if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) { Start-Process powershell.exe "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`"" -Verb RunAs; exit }
Invoke-WebRequest https://chocolatey.org/install.ps1 -UseBasicParsing | iex
Update-Environment-Path
# 3. Git for source code management.
choco install git --yes --params '/GitAndUnixToolsOnPath'
Update-Environment-Path
# 4. Node for node and npm.
# 10.14.1 to avoid e2e problems
choco install nodejs --version 10.14.1 --yes
Update-Environment-Path
# 5. VS Code
choco install visualstudiocode --yes # includes dotnet
Update-Environment-Path
code --install-extension CoenraadS.bracket-pair-colorizer
code --install-extension ms-vscode.PowerShell
code --install-extension ms-vscode.csharp
code --install-extension eg2.vscode-npm-script
code --install-extension christian-kohler.npm-intellisense
# 6. major browsers
choco install googlechrome --yes
choco install firefox --yes
Update-Environment-Path
Write-Output "Complete"
@@ -0,0 +1,2 @@
User-Agent: *
Disallow: /
@@ -0,0 +1,6 @@
$font-family-base: Arial, sans-serif;
$primary: #005B9A;
$secondary: #7ca550; // #FCCA10;
$warning: #F5961E;
$body-bg: #FFFFFF;
@@ -0,0 +1,30 @@
import { Validators } from '@angular/forms';
export class AdminGroups {
private static DATE_PATTERN = /^(0[1-9]|1[0-2])\/(0[1-9]|1\d|2\d|3[01])\/(19|20)\d{2}$/;
public static readonly FILTER = {
group: 'filterInformation',
fields: [
{field: 'startDate', validation: [Validators.required, Validators.pattern(AdminGroups.DATE_PATTERN)]},
{field: 'endDate', validation: [Validators.required, Validators.pattern(AdminGroups.DATE_PATTERN)]},
{field: 'loanType', validation: []},
{field: 'branch', validation: []},
{field: 'decisioned', validation: []},
{field: 'submitted', validation: []},
{field: 'inProgress', validation: []},
{field: 'error', validation: []},
{field: 'deleted', validation: []},
]
};
public static readonly CONFIG = {
group: 'configInformation',
fields: [
{field: 'appStatus', validation: []},
]
};
}
@@ -0,0 +1,31 @@
import { RouterModule, Routes } from '@angular/router';
import { NgModule } from '@angular/core';
import { AdminComponent } from './admin.component';
import { LoanTableComponent } from './loan-table/loan-table.component';
import { LoanDataComponent } from './loan-data/loan-data.component';
import { BranchConfigComponent } from './branch-config/branch-config.component';
import { BranchNameConfigComponent } from './branch-name-config/branch-name-config.component';
import { SystemConfigComponent } from './system-config/system-config.component';
import { SchumerPreviewComponent } from './schumer-boxes/schumer-preview.component';
const routes: Routes = [
{
path: '',
component: AdminComponent,
children: [
{path: 'branch-config', component: BranchConfigComponent},
{path: 'branch-name-config', component: BranchNameConfigComponent},
{path: 'loan-table', component: LoanTableComponent},
{path: 'system-config', component: SystemConfigComponent},
{path: 'schumer-preview', component: SchumerPreviewComponent},
{path: 'loan-data/:id', component: LoanDataComponent},
{path: '', redirectTo: '/admin', pathMatch: 'prefix'},
]
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class AdminRoutingModule {}
@@ -0,0 +1,7 @@
<div *ngIf ="router.url == '/admin'">
<lw-admin-landing></lw-admin-landing>
</div>
<div>
<router-outlet></router-outlet>
</div>

Some files were not shown because too many files have changed in this diff Show More