Merge pull request #1087 from dod-ccpo/to-step3-testing

Initial JS tests for the Vue TOForm component.
This commit is contained in:
dandds 2019-09-23 10:32:23 -04:00 committed by GitHub
commit 46f8e07729
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 538 additions and 68 deletions

View File

@ -3,7 +3,7 @@
"files": "^.secrets.baseline$",
"lines": null
},
"generated_at": "2019-09-13T17:44:56Z",
"generated_at": "2019-09-20T19:20:43Z",
"plugins_used": [
{
"base64_limit": 4.5,
@ -199,5 +199,5 @@
}
]
},
"version": "0.12.5"
"version": "0.12.6"
}

View File

@ -44,6 +44,7 @@ honcho = "*"
blinker = "*"
pytest-mock = "*"
detect-secrets = "*"
beautifulsoup4 = "*"
[requires]
python_version = "3.7.3"

136
Pipfile.lock generated
View File

@ -1,7 +1,7 @@
{
"_meta": {
"hash": {
"sha256": "bf3b598c052193f70249da97ac746bc53aeb72f45a4515e10945a4274aba7b18"
"sha256": "8eb62f8620ec951cbef680341d18a184e9661cd28e4c3761e9679dc840fd1888"
},
"pipfile-spec": 6,
"requires": {
@ -18,10 +18,10 @@
"default": {
"alembic": {
"hashes": [
"sha256:4a4811119efbdc5259d1f4c8f6de977b36ad3bcc919f59a29c2960c5ef9149e4"
"sha256:5609afbb2ab142a991b15ae436347c475f8a517f1610f2fd1b09cdca7c311f3f"
],
"index": "pypi",
"version": "==1.1.0"
"version": "==1.2.0"
},
"amqp": {
"hashes": [
@ -32,11 +32,11 @@
},
"apache-libcloud": {
"hashes": [
"sha256:8f133038710257d39f9092ccaea694e31f7f4fe02c11d7fcc2674bc60a9448b6",
"sha256:d876f8c4d8aecf32f41f3a4d6ed1cebdf33b8b8f73df0aebc5280789fa806c60"
"sha256:201751f738109f25d58dcdfb5804e17216e0dc8f68b522e9e26ac16e0b9ff2ea",
"sha256:40215db1bd489d17dc1abfdb289d7f035313c7297b6a7462c79d8287cbbeae91"
],
"index": "pypi",
"version": "==2.5.0"
"version": "==2.6.0"
},
"asn1crypto": {
"hashes": [
@ -85,18 +85,18 @@
},
"boto3": {
"hashes": [
"sha256:366a1f3ec37b9434f25247cbe876f9ca1b53d35e35af18f74c735445100b4bc4",
"sha256:e7718b48cd073ad59a99a33d14252319dfaf550be3682b0c6a58da052fb05fcc"
"sha256:0e4d047feb4d7d701e9b2107f10bb8d674952243385cd35d0b413a273c299751",
"sha256:67f957389cf56fb4c24c1093c6d58baebe6cf18139f6dca0f8a177239b0a4f8c"
],
"index": "pypi",
"version": "==1.9.217"
"version": "==1.9.232"
},
"botocore": {
"hashes": [
"sha256:68a0a22ca4e0e7e7ab482f63e21debfe402841fc49b8503dec0a7307b565d774",
"sha256:7a213b876e58b1b5380cf30faa05ba45073692ad4a3cc803ba763082a36436bb"
"sha256:724d2349198c6f15f3cee0c0e4d33ecf4435e6d0db311bb79a3a28f6cf5a4090",
"sha256:a57a8fd0145c68e31bb4baab549b27a12f6695068c8dd5f2901d8dc06572dbeb"
],
"version": "==1.12.217"
"version": "==1.12.232"
},
"celery": {
"hashes": [
@ -108,10 +108,10 @@
},
"certifi": {
"hashes": [
"sha256:046832c04d4e752f37383b628bc601a7ea7211496b4638f6514d0e5b9acc4939",
"sha256:945e3ba63a0b9f577b1395204e13c3a231f9bc0223888be653286534e5873695"
"sha256:e4f3620cfea4f83eedc95b24abd9cd56f3c4b146dd0177e83a21b4eb49e21e50",
"sha256:fd7c7c74727ddcf00e9acd26bba8da604ffec95bf1c2144e67aff7a8b50e6cef"
],
"version": "==2019.6.16"
"version": "==2019.9.11"
},
"cffi": {
"hashes": [
@ -237,10 +237,10 @@
},
"importlib-metadata": {
"hashes": [
"sha256:23d3d873e008a513952355379d93cbcab874c58f4f034ff657c7a87422fa64e8",
"sha256:80d2de76188eabfbfcf27e6a37342c2827801e59c4cc14b0371c56fed43820e3"
"sha256:aa18d7378b00b40847790e7c27e11673d7fed219354109d0e7b9e5b25dc3ad26",
"sha256:d5f18a79777f3aa179c145737780282e27b508fc8fd688cb17c7a813e8bd39af"
],
"version": "==0.19"
"version": "==0.23"
},
"itsdangerous": {
"hashes": [
@ -409,10 +409,10 @@
},
"pytzdata": {
"hashes": [
"sha256:c0c8316eaf6c25ba45816390a1a45c39790767069b3275c5f7de3ddf773eb810",
"sha256:e8a91952afd853642a49f0713caac3e15a5306855ff4a47af4ddec5b7dd23a09"
"sha256:84c52b9a47d097fcd483f047a544979de6c3a86e94c845e3569e9f8acd0fa071",
"sha256:fac06f7cdfa903188dc4848c655e4adaee67ee0f2fe08e7daf815cf2a761ee5e"
],
"version": "==2019.2"
"version": "==2019.3"
},
"pyyaml": {
"hashes": [
@ -480,11 +480,11 @@
},
"urllib3": {
"hashes": [
"sha256:b246607a25ac80bedac05c6f282e3cdaf3afb65420fd024ac94435cabe6e18d1",
"sha256:dbe59173209418ae49d485b87d1681aefa36252ee85884c31346debd19463232"
"sha256:2f3eadfea5d92bc7899e75b5968410b749a054b492d5a6379c1344a1481bc2cb",
"sha256:9c6c593cb28f52075016307fc26b0a0f8e82bc7d1ff19aaaa959b91710a56c47"
],
"markers": "python_version >= '3.4'",
"version": "==1.25.3"
"version": "==1.25.5"
},
"vine": {
"hashes": [
@ -502,11 +502,11 @@
},
"werkzeug": {
"hashes": [
"sha256:87ae4e5b5366da2347eb3116c0e6c681a0e939a33b2805e2c0cbd282664932c4",
"sha256:a13b74dd3c45f758d4ebdb224be8f1ab8ef58b3c0ffc1783a8c7d9f4f50227e6"
"sha256:7280924747b5733b246fe23972186c6b348f9ae29724135a6dfc1e53cea433e7",
"sha256:e5f4a1f98b52b18a93da705a7458e55afb26f32bff83ff5d19189f92462d65c4"
],
"index": "pypi",
"version": "==0.15.5"
"version": "==0.16.0"
},
"wtforms": {
"hashes": [
@ -582,6 +582,15 @@
"index": "pypi",
"version": "==1.6.2"
},
"beautifulsoup4": {
"hashes": [
"sha256:05668158c7b85b791c5abde53e50265e16f98ad601c402ba44d70f96c4159612",
"sha256:25288c9e176f354bf277c0a10aa96c782a6a18a17122dba2e8cec4a97e03343b",
"sha256:f040590be10520f2ea4c2ae8c3dae441c7cfff5308ec9d58a0ec0c1b8f81d469"
],
"index": "pypi",
"version": "==4.8.0"
},
"black": {
"hashes": [
"sha256:09a9dcb7c46ed496a9850b76e4e825d6049ecd38b611f1224857a79bd985a8cf",
@ -599,10 +608,10 @@
},
"certifi": {
"hashes": [
"sha256:046832c04d4e752f37383b628bc601a7ea7211496b4638f6514d0e5b9acc4939",
"sha256:945e3ba63a0b9f577b1395204e13c3a231f9bc0223888be653286534e5873695"
"sha256:e4f3620cfea4f83eedc95b24abd9cd56f3c4b146dd0177e83a21b4eb49e21e50",
"sha256:fd7c7c74727ddcf00e9acd26bba8da604ffec95bf1c2144e67aff7a8b50e6cef"
],
"version": "==2019.6.16"
"version": "==2019.9.11"
},
"chardet": {
"hashes": [
@ -666,11 +675,11 @@
},
"detect-secrets": {
"hashes": [
"sha256:33593cbf7099ced595e7371fcee31c815a237419de2869d571bbdb651a125d4c",
"sha256:7b8e6d521f5a164ff17dbe3d2691eb85f842133d4e6bb7a23eeb461a0ab4e215"
"sha256:7e1820a3c4ac412a7a2cec13075c274ae4bfc9167b4b831ad3c7f0e6208c9488",
"sha256:bacb5842f149f39799409039fafb1902554ac0c71a9764cc8a8ffab85f99efc1"
],
"index": "pypi",
"version": "==0.12.5"
"version": "==0.12.6"
},
"docopt": {
"hashes": [
@ -688,10 +697,10 @@
},
"faker": {
"hashes": [
"sha256:1d3f700e8dfcefd6e657118d71405d53e86974448aba78884f119bbd84c0cddf",
"sha256:d5366e120191c5610fceeebfe1c298dc46da0277096f639c6dd7e2eaee0fa547"
"sha256:45cc9cca3de8beba5a2da3bd82a6e5544f53da1a702645c8485f682366c15026",
"sha256:a6459ff518d1fc6ee2238a7209e6c899517872c7e1115510279033ffe6fe8ef3"
],
"version": "==2.0.1"
"version": "==2.0.2"
},
"flask": {
"hashes": [
@ -732,10 +741,10 @@
},
"importlib-metadata": {
"hashes": [
"sha256:23d3d873e008a513952355379d93cbcab874c58f4f034ff657c7a87422fa64e8",
"sha256:80d2de76188eabfbfcf27e6a37342c2827801e59c4cc14b0371c56fed43820e3"
"sha256:aa18d7378b00b40847790e7c27e11673d7fed219354109d0e7b9e5b25dc3ad26",
"sha256:d5f18a79777f3aa179c145737780282e27b508fc8fd688cb17c7a813e8bd39af"
],
"version": "==0.19"
"version": "==0.23"
},
"ipdb": {
"hashes": [
@ -746,11 +755,11 @@
},
"ipython": {
"hashes": [
"sha256:1d3a1692921e932751bc1a1f7bb96dc38671eeefdc66ed33ee4cbc57e92a410e",
"sha256:537cd0176ff6abd06ef3e23f2d0c4c2c8a4d9277b7451544c6cbf56d1c79a83d"
"sha256:c4ab005921641e40a68e405e286e7a1fcc464497e14d81b6914b4fd95e5dee9b",
"sha256:dd76831f065f17bddd7eaa5c781f5ea32de5ef217592cf019e34043b56895aa1"
],
"index": "pypi",
"version": "==7.7.0"
"version": "==7.8.0"
},
"ipython-genutils": {
"hashes": [
@ -872,10 +881,10 @@
},
"pbr": {
"hashes": [
"sha256:56e52299170b9492513c64be44736d27a512fa7e606f21942160b68ce510b4bc",
"sha256:9b321c204a88d8ab5082699469f52cc94c5da45c51f114113d01b3d993c24cdf"
"sha256:2c8e420cd4ed4cec4e7999ee47409e876af575d4c35a45840d59e8b5f3155ab8",
"sha256:b32c8ccaac7b1a20c0ce00ce317642e6cf231cf038f9875e0280e28af5bf7ac9"
],
"version": "==5.4.2"
"version": "==5.4.3"
},
"pexpect": {
"hashes": [
@ -894,10 +903,10 @@
},
"pluggy": {
"hashes": [
"sha256:0825a152ac059776623854c1543d65a4ad408eb3d33ee114dff91e57ec6ae6fc",
"sha256:b9817417e95936bf75d85d3f8767f7df6cdde751fc40aed3bb3074cbcb77757c"
"sha256:0db4b7601aae1d35b4a033282da476845aa19185c1e6964b25cf324b5e4ec3e6",
"sha256:fa5fa1622fa6dd5c030e9cad086fa19ef6a0cf6d7a2d12318e10cb49d6d68f34"
],
"version": "==0.12.0"
"version": "==0.13.0"
},
"prompt-toolkit": {
"hashes": [
@ -1039,19 +1048,26 @@
],
"version": "==2.0.5"
},
"soupsieve": {
"hashes": [
"sha256:8662843366b8d8779dec4e2f921bebec9afd856a5ff2e82cd419acc5054a1a92",
"sha256:a5a6166b4767725fd52ae55fee8c8b6137d9a51e9f1edea461a062a759160118"
],
"version": "==1.9.3"
},
"stevedore": {
"hashes": [
"sha256:7be098ff53d87f23d798a7ce7ae5c31f094f3deb92ba18059b1aeb1ca9fec0a0",
"sha256:7d1ce610a87d26f53c087da61f06f9b7f7e552efad2a7f6d2322632b5f932ea2"
"sha256:01d9f4beecf0fbd070ddb18e5efb10567801ba7ef3ddab0074f54e3cd4e91730",
"sha256:e0739f9739a681c7a1fda76a102b65295e96a144ccdb552f2ae03c5f0abe8a14"
],
"version": "==1.30.1"
"version": "==1.31.0"
},
"text-unidecode": {
"hashes": [
"sha256:5a1375bb2ba7968740508ae38d92e1f889a0832913cb1c447d5e2046061a396d",
"sha256:801e38bd550b943563660a91de8d4b6fa5df60a542be9093f7abf819f86050cc"
"sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8",
"sha256:bad6603bb14d279193107714b288be206cac565dfa49aa5b105294dd5c4aab93"
],
"version": "==1.2"
"version": "==1.3"
},
"toml": {
"hashes": [
@ -1090,11 +1106,11 @@
},
"urllib3": {
"hashes": [
"sha256:b246607a25ac80bedac05c6f282e3cdaf3afb65420fd024ac94435cabe6e18d1",
"sha256:dbe59173209418ae49d485b87d1681aefa36252ee85884c31346debd19463232"
"sha256:2f3eadfea5d92bc7899e75b5968410b749a054b492d5a6379c1344a1481bc2cb",
"sha256:9c6c593cb28f52075016307fc26b0a0f8e82bc7d1ff19aaaa959b91710a56c47"
],
"markers": "python_version >= '3.4'",
"version": "==1.25.3"
"version": "==1.25.5"
},
"watchdog": {
"hashes": [
@ -1111,11 +1127,11 @@
},
"werkzeug": {
"hashes": [
"sha256:87ae4e5b5366da2347eb3116c0e6c681a0e939a33b2805e2c0cbd282664932c4",
"sha256:a13b74dd3c45f758d4ebdb224be8f1ab8ef58b3c0ffc1783a8c7d9f4f50227e6"
"sha256:7280924747b5733b246fe23972186c6b348f9ae29724135a6dfc1e53cea433e7",
"sha256:e5f4a1f98b52b18a93da705a7458e55afb26f32bff83ff5d19189f92462d65c4"
],
"index": "pypi",
"version": "==0.15.5"
"version": "==0.16.0"
},
"wrapt": {
"hashes": [

View File

@ -172,7 +172,7 @@ export default {
},
_emitChange: function(name, value, valid) {
emitEvent('field-change', this, { value, name })
emitEvent('field-change', this, { value, name, valid })
},
},

View File

@ -0,0 +1,67 @@
import { mount } from '@vue/test-utils'
import toForm from '../to_form'
import clinFields from '../../clin_fields'
import { makeTestWrapper } from '../../../test_utils/component_test_helpers'
const TOFormWrapper = makeTestWrapper({
components: { toForm },
templatePath: 'to_form.html',
})
describe('TOForm Test', () => {
it('should allow users to add new CLINs', () => {
const wrapper = mount(TOFormWrapper, {
propsData: {
initialData: {},
},
})
expect(wrapper.findAll(clinFields).length).toBe(1)
wrapper.find('#add-clin').trigger('click')
expect(wrapper.findAll(clinFields).length).toBe(2)
})
it('should not enable the save button until the form is complete and valid', () => {
const wrapper = mount(TOFormWrapper, {
propsData: {
initialData: {},
},
})
const submit = wrapper.find('input[type=submit]')
function expectSubmitIsDisabled() {
expect(submit.attributes('disabled')).toEqual('disabled')
}
expectSubmitIsDisabled()
// begin filling in the form; check at every submit button is disabled
wrapper.find('input#clins-0-number').setValue('0001')
expectSubmitIsDisabled()
wrapper.find('input#clins-0-obligated_amount').setValue('50000')
expectSubmitIsDisabled()
wrapper.find('input#clins-0-total_amount').setValue('60000')
expectSubmitIsDisabled()
wrapper.findAll('input[name="date-month"]').setValue('12')
expectSubmitIsDisabled()
wrapper.findAll('input[name="date-day"]').setValue('01')
expectSubmitIsDisabled()
wrapper
.findAll('input[name="date-year"]')
.at(0)
.setValue('2020')
expectSubmitIsDisabled()
wrapper
.findAll('input[name="date-year"]')
.at(1)
.setValue('2021')
expectSubmitIsDisabled()
// need to trigger the change function on the hidden date inputs so that
// the corresponding event fires to notify the parent form that it is valid
wrapper.find('input[name="clins-0-start_date"]').trigger('change')
wrapper.find('input[name="clins-0-end_date"]').trigger('change')
// check save button is enabled
expect(submit.attributes('disabled')).toBeUndefined()
})
})

View File

@ -3,9 +3,10 @@
inline-template
key='datafield'
v-bind:initial-checked='initialvalue'
v-bind:optional=false
>
<div>
<div class='usa-input '>
<div class='usa-input ' v-bind:class="[{ 'checked': isChecked }]">
<fieldset data-ally-disabled="true" v-on:change="onInput" class="usa-input__choices ">
<legend>
@ -16,6 +17,5 @@
</legend>
</fieldset>
</div>
</div>
</checkboxinput>

View File

@ -0,0 +1,341 @@
<to-form inline-template="">
<form action="/task_orders//form/step_3" autocomplete="off" enctype="multipart/form-data" id="to_form" method="POST">
<div class="sticky-cta" v-sticky='{ "stickyBitStickyOffset": 76 }'>
<div class="sticky-cta-container">
<div class="sticky-cta-text">
<h3>Add Task Order (step 3 of 5)</h3>
</div>
<div class="sticky-cta-buttons">
<span class="action-group">
<input :disabled="!canSave" class="usa-button usa-button-primary" form="to_form" tabindex="0" type="submit" value="Next: Review Task Order"/>
<a class="usa-button usa-button-secondary" href="/task_orders//form/step_2">
Previous
</a>
<a class="action-group__action icon-link" v-on:click="openModal('cancel')">
Cancel
</a>
</span>
</div>
</div>
</div>
<div v-cloak="" v-show="$root.activeModal === 'cancel'">
<div class="modal modal--dismissable" id="modal--cancel">
<div class="modal__container">
<div aria-modal="true" class="modal__dialog" role="dialog">
<div class="modal__body">
<div class="task-order__modal-cancel">
<h1>Do you want to save this draft?</h1>
<div class="task-order__modal-cancel_buttons">
<button class="usa-button usa-button-primary" formaction="/portfolios/e4edf994-04f4-4aaa-ba30-39507e1068a8/task_orders/form/cancel?save=False" type="submit">No, delete it</button>
<button class="usa-button usa-button-primary" formaction="/portfolios/e4edf994-04f4-4aaa-ba30-39507e1068a8/task_orders/form/cancel?save=True" type="submit">Yes, save for later</button>
</div>
</div>
<button class="icon-link modal__dismiss" type="button" v-on:click='closeModal("cancel")'>
<span aria-hidden="true" class="icon icon--x"><svg viewbox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M2 2l12 12M14 15c-.256 0-.512-.098-.707-.293l-12-12c-.391-.391-.391-1.023 0-1.414s1.023-.391 1.414 0l12 12c.391.391.391 1.023 0 1.414-.195.195-.451.293-.707.293zm0-13L2 14"></path><path d="M2 15c-.256 0-.512-.098-.707-.293-.391-.391-.391-1.023 0-1.414l12-12c.391-.391 1.023-.391 1.414 0s.391 1.023 0 1.414l-12 12C2.512 14.902 2.256 15 2 15z"></path></svg>
</span>
<span>
Close
</span>
</button>
</div>
</div>
</div>
</div>
</div>
<div class="task-order">
<div>
<div class="task-order__header">
<div class="h2">
Enter Contract Line Items
</div>
<p>
<strong>Task Order Number:</strong> 1234567890123
</p>
<p>
Refer to your task order to locate your Contract Line Item Numbers (CLINs).
</p>
</div>
<div v-for="clin in clins">
<clin-fields inline-template="" v-bind:contract-end="'2022-09-14'" v-bind:contract-start="'2019-09-14'" v-bind:initial-clin-index="clinIndex" v-bind:initial-clin-type="'JEDI_CLIN_1'">
<div class="clin-card" v-if="showClin">
<div class="card__title">
<span class="h4" v-html="clinTitle"></span>
<button class="icon-link icon-link__remove-clin" type="button" v-if="$parent.clinIndex &gt; 0" v-on:click="openModal(removeModalId)">
<span aria-hidden="true" class="icon icon--x"><svg viewbox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M2 2l12 12M14 15c-.256 0-.512-.098-.707-.293l-12-12c-.391-.391-.391-1.023 0-1.414s1.023-.391 1.414 0l12 12c.391.391.391 1.023 0 1.414-.195.195-.451.293-.707.293zm0-13L2 14"></path><path d="M2 15c-.256 0-.512-.098-.707-.293-.391-.391-.391-1.023 0-1.414l12-12c.391-.391 1.023-.391 1.414 0s.391 1.023 0 1.414l-12 12C2.512 14.902 2.256 15 2 15z"></path></svg>
</span>
</button>
</div>
<div class="card">
<div class="form-row">
<div class="h4 clin-card__title">
CLIN Details
</div>
</div>
<div class="form-row">
<div class="form-col">
<textinput :name="'clins-' + clinIndex + '-number'" :watch="true" inline-template="">
<div v-bind:class="['usa-input usa-input--validation--' + validation, { 'usa-input--error': showError, 'usa-input--success': showValid, 'usa-input--validation--paragraph': paragraph, 'no-max-width': noMaxWidth }]">
<label :for="name">
<span v-show="showError">
<span aria-hidden="true" class="icon icon--alert icon-validation"><svg fill="#fdb81e" viewbox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
<path d="M8 16c-4.411 0-8-3.589-8-8s3.589-8 8-8 8 3.589 8 8-3.589 8-8 8zM8 2C4.691 2 2 4.691 2 8s2.691 6 6 6 6-2.691 6-6-2.691-6-6-6zm0 8c-.552 0-1-.447-1-1V4c0-.552.448-1 1-1s1 .448 1 1v5c0 .553-.448 1-1 1zm0 3c-.26 0-.52-.11-.71-.29-.18-.19-.29-.45-.29-.71 0-.271.11-.521.29-.71.38-.37 1.05-.37 1.42 0 .18.189.29.45.29.71s-.11.52-.29.71c-.19.18-.45.29-.71.29z"></path>
</svg>
</span>
</span>
<span v-show="showValid">
<span aria-hidden="true" class="icon icon--ok icon-validation"><svg aria-hidden="true" class="svg-inline--fa fa-check-circle fa-w-16" data-icon="check-circle" data-prefix="fas" focusable="false" role="img" viewbox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><path d="M504 256c0 136.967-111.033 248-248 248S8 392.967 8 256 119.033 8 256 8s248 111.033 248 248zM227.314 387.314l184-184c6.248-6.248 6.248-16.379 0-22.627l-22.627-22.627c-6.248-6.249-16.379-6.249-22.628 0L216 308.118l-70.059-70.059c-6.248-6.248-16.379-6.248-22.628 0l-22.627 22.627c-6.248 6.248-6.248 16.379 0 22.627l104 104c6.249 6.249 16.379 6.249 22.628.001z" fill="currentColor"></path></svg></span>
</span>
<div class="usa-input__title">CLIN</div>
</label>
<masked-input :id="name" ref="input" type="text" v-bind:aria-invalid="showError" v-bind:keep-char-positions="keepCharPositions" v-bind:mask="mask" v-bind:pipe="pipe" v-bind:value="value" v-on:blur="onBlur" v-on:change="onChange" v-on:input="onInput">
</masked-input>
<input :name="name" type="hidden" v-bind:value="rawValue">
<template v-if="showError">
<span class="usa-input__message" v-html="validationError"></span>
</template>
<template v-else="">
<span class="usa-input__message"></span>
</template>
</input></div>
</textinput>
</div>
</div>
<div class="form-row">
<div class="form-col">
<optionsinput :name="'clins-' + clinIndex + '-jedi_clin_type'" :optional="false" :watch="true" inline-template="">
<div v-bind:class="['usa-input', { 'usa-input--error': showError, 'usa-input--success': showValid }]">
<fieldset class="usa-input__choices" data-ally-disabled="true" v-on:change="onInput">
<legend>
<div class="usa-input__title">
Corresponding IDIQ CLIN
</div>
</legend>
<select :id="name" :name="name">
<option value="JEDI_CLIN_1">IaaS/PaaS (IDIQ CLIN 0001)</option>
<option value="JEDI_CLIN_2">IDIQ CLIN 0002</option>
<option value="JEDI_CLIN_3">IDIQ CLIN 0003</option>
<option value="JEDI_CLIN_4">IDIQ CLIN 0004</option>
</select>
</fieldset>
</div>
</optionsinput>
</div>
</div>
<hr/>
<div class="form-row">
<div class="h4 clin-card__title">
CLIN Funding
</div>
</div>
<div class="form-row">
<div class="form-col">
<clindollaramount :funding-valid="true" :key="'clins-' + clinIndex + '-' + 'total' + '_amount'" :name="'clins-' + clinIndex + '-' + 'total' + '_amount'" :watch="true" inline-template="" v-cloak="" validation="clinDollars">
<div v-bind:class="['usa-input usa-input--validation--dollars', { 'usa-input--error': showFundingError, 'usa-input--success': showFundingValid}]">
<label :for="name">
<div class="usa-input__title">Total CLIN Value</div>
<span v-show="showFundingError">
<span aria-hidden="true" class="icon icon--alert icon-validation"><svg fill="#fdb81e" viewbox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
<path d="M8 16c-4.411 0-8-3.589-8-8s3.589-8 8-8 8 3.589 8 8-3.589 8-8 8zM8 2C4.691 2 2 4.691 2 8s2.691 6 6 6 6-2.691 6-6-2.691-6-6-6zm0 8c-.552 0-1-.447-1-1V4c0-.552.448-1 1-1s1 .448 1 1v5c0 .553-.448 1-1 1zm0 3c-.26 0-.52-.11-.71-.29-.18-.19-.29-.45-.29-.71 0-.271.11-.521.29-.71.38-.37 1.05-.37 1.42 0 .18.189.29.45.29.71s-.11.52-.29.71c-.19.18-.45.29-.71.29z"></path>
</svg>
</span>
</span>
<span v-show="showFundingValid">
<span aria-hidden="true" class="icon icon--ok icon-validation"><svg aria-hidden="true" class="svg-inline--fa fa-check-circle fa-w-16" data-icon="check-circle" data-prefix="fas" focusable="false" role="img" viewbox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><path d="M504 256c0 136.967-111.033 248-248 248S8 392.967 8 256 119.033 8 256 8s248 111.033 248 248zM227.314 387.314l184-184c6.248-6.248 6.248-16.379 0-22.627l-22.627-22.627c-6.248-6.249-16.379-6.249-22.628 0L216 308.118l-70.059-70.059c-6.248-6.248-16.379-6.248-22.628 0l-22.627 22.627c-6.248 6.248-6.248 16.379 0 22.627l104 104c6.249 6.249 16.379 6.249 22.628.001z" fill="currentColor"></path></svg></span>
</span>
</label>
<masked-input :id="name" ref="input" type="text" v-bind:aria-invalid="showError" v-bind:keep-char-positions="keepCharPositions" v-bind:mask="mask" v-bind:pipe="pipe" v-bind:value="value" v-on:blur="onBlur" v-on:change="onChange" v-on:input="onInput">
</masked-input>
<input :name="name" type="hidden" v-bind:value="rawValue"/>
<template v-if="!fundingValid">
<span class="usa-input__message">Obligated amount must be less than or equal to total amount</span>
</template>
<template v-else-if="showError">
<span class="usa-input__message" v-html="validationError"></span>
</template>
<template v-else="">
<span class="usa-input__message"></span>
</template>
</div>
</clindollaramount>
</div>
</div>
<div class="form-row">
<div class="form-col">
<clindollaramount :funding-valid="fundingValid" :key="'clins-' + clinIndex + '-' + 'obligated' + '_amount'" :name="'clins-' + clinIndex + '-' + 'obligated' + '_amount'" :watch="true" inline-template="" v-cloak="" validation="clinDollars">
<div v-bind:class="['usa-input usa-input--validation--dollars', { 'usa-input--error': showFundingError, 'usa-input--success': showFundingValid}]">
<label :for="name">
<div class="usa-input__title">Obligated Funds</div>
<span v-show="showFundingError">
<span aria-hidden="true" class="icon icon--alert icon-validation"><svg fill="#fdb81e" viewbox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
<path d="M8 16c-4.411 0-8-3.589-8-8s3.589-8 8-8 8 3.589 8 8-3.589 8-8 8zM8 2C4.691 2 2 4.691 2 8s2.691 6 6 6 6-2.691 6-6-2.691-6-6-6zm0 8c-.552 0-1-.447-1-1V4c0-.552.448-1 1-1s1 .448 1 1v5c0 .553-.448 1-1 1zm0 3c-.26 0-.52-.11-.71-.29-.18-.19-.29-.45-.29-.71 0-.271.11-.521.29-.71.38-.37 1.05-.37 1.42 0 .18.189.29.45.29.71s-.11.52-.29.71c-.19.18-.45.29-.71.29z"></path>
</svg>
</span>
</span>
<span v-show="showFundingValid">
<span aria-hidden="true" class="icon icon--ok icon-validation"><svg aria-hidden="true" class="svg-inline--fa fa-check-circle fa-w-16" data-icon="check-circle" data-prefix="fas" focusable="false" role="img" viewbox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><path d="M504 256c0 136.967-111.033 248-248 248S8 392.967 8 256 119.033 8 256 8s248 111.033 248 248zM227.314 387.314l184-184c6.248-6.248 6.248-16.379 0-22.627l-22.627-22.627c-6.248-6.249-16.379-6.249-22.628 0L216 308.118l-70.059-70.059c-6.248-6.248-16.379-6.248-22.628 0l-22.627 22.627c-6.248 6.248-6.248 16.379 0 22.627l104 104c6.249 6.249 16.379 6.249 22.628.001z" fill="currentColor"></path></svg></span>
</span>
</label>
<masked-input :id="name" ref="input" type="text" v-bind:aria-invalid="showError" v-bind:keep-char-positions="keepCharPositions" v-bind:mask="mask" v-bind:pipe="pipe" v-bind:value="value" v-on:blur="onBlur" v-on:change="onChange" v-on:input="onInput">
</masked-input>
<input :name="name" type="hidden" v-bind:value="rawValue"/>
<template v-if="!fundingValid">
<span class="usa-input__message">Obligated amount must be less than or equal to total amount</span>
</template>
<template v-else-if="showError">
<span class="usa-input__message" v-html="validationError"></span>
</template>
<template v-else="">
<span class="usa-input__message"></span>
</template>
</div>
</clindollaramount>
</div>
</div>
<div class="h5 clin-card__title">Percent Obligated</div>
<p v-html="percentObligated"></p>
<hr/>
<div class="form-row">
<div class="h4 clin-card__title">
Period of Performance
</div>
</div>
<div class="form-row">
<div class="form-col">
<date-selector :name-tag="'clins-' + clinIndex + '-start_date'" :optional="false" :watch="true" inline-template="">
<fieldset class="usa-input date-picker" v-bind:class="{ 'usa-input--success': isDateValid &amp;&amp; showValidation }">
<legend>
<div class="usa-input__title">
Start Date
</div>
<p class="usa-input__help">
For example: 07 04 1776
</p>
</legend>
<div class="date-picker-component">
<input :name="name" type="hidden" v-bind:value="formattedDate" v-on:change="onInput"/>
<div class="usa-form-group usa-form-group-month">
<label>Month</label>
<input max="12" maxlength="2" min="1" name="date-month" type="number" v-bind:class="{ 'usa-input-error': (month &amp;&amp; !isMonthValid) }" v-model="month" v-on:change="onInput"/>
</div>
<div class="usa-form-group usa-form-group-day">
<label>Day</label>
<input maxlength="2" min="1" name="date-day" type="number" v-bind:class="{ 'usa-input-error': (day &amp;&amp; !isDayValid) }" v-bind:max="daysMaxCalculation" v-model="day" v-on:change="onInput"/>
</div>
<div class="usa-form-group usa-form-group-year">
<label>Year</label>
<input maxlength="4" name="date-year" type="number" v-model="year" v-on:change="onInput"/>
</div>
<div class="usa-form-group-date-ok" v-if="isDateValid">
<span aria-hidden="true" class="icon icon--ok icon--green"><svg aria-hidden="true" class="svg-inline--fa fa-check-circle fa-w-16" data-icon="check-circle" data-prefix="fas" focusable="false" role="img" viewbox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><path d="M504 256c0 136.967-111.033 248-248 248S8 392.967 8 256 119.033 8 256 8s248 111.033 248 248zM227.314 387.314l184-184c6.248-6.248 6.248-16.379 0-22.627l-22.627-22.627c-6.248-6.249-16.379-6.249-22.628 0L216 308.118l-70.059-70.059c-6.248-6.248-16.379-6.248-22.628 0l-22.627 22.627c-6.248 6.248-6.248 16.379 0 22.627l104 104c6.249 6.249 16.379 6.249 22.628.001z" fill="currentColor"></path></svg></span>
</div>
</div>
</fieldset>
</date-selector>
</div>
</div>
<div class="form-row">
<div class="form-col">
<date-selector :name-tag="'clins-' + clinIndex + '-end_date'" :optional="false" :watch="true" inline-template="">
<fieldset class="usa-input date-picker" v-bind:class="{ 'usa-input--success': isDateValid &amp;&amp; showValidation }">
<legend>
<div class="usa-input__title">
End Date
</div>
<div aria-live="polite" class="usa-alert usa-alert-info" role="alert">
<div class="usa-alert-body">
<p class="usa-alert-text">
A CLIN's period of performance must end before September 14, 2022.
</p>
</div>
</div>
<p class="usa-input__help">
For example: 07 04 1776
</p>
</legend>
<div class="date-picker-component">
<input :name="name" type="hidden" v-bind:value="formattedDate" v-on:change="onInput"/>
<div class="usa-form-group usa-form-group-month">
<label>Month</label>
<input max="12" maxlength="2" min="1" name="date-month" type="number" v-bind:class="{ 'usa-input-error': (month &amp;&amp; !isMonthValid) }" v-model="month" v-on:change="onInput"/>
</div>
<div class="usa-form-group usa-form-group-day">
<label>Day</label>
<input maxlength="2" min="1" name="date-day" type="number" v-bind:class="{ 'usa-input-error': (day &amp;&amp; !isDayValid) }" v-bind:max="daysMaxCalculation" v-model="day" v-on:change="onInput"/>
</div>
<div class="usa-form-group usa-form-group-year">
<label>Year</label>
<input maxlength="4" name="date-year" type="number" v-model="year" v-on:change="onInput"/>
</div>
<div class="usa-form-group-date-ok" v-if="isDateValid">
<span aria-hidden="true" class="icon icon--ok icon--green"><svg aria-hidden="true" class="svg-inline--fa fa-check-circle fa-w-16" data-icon="check-circle" data-prefix="fas" focusable="false" role="img" viewbox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><path d="M504 256c0 136.967-111.033 248-248 248S8 392.967 8 256 119.033 8 256 8s248 111.033 248 248zM227.314 387.314l184-184c6.248-6.248 6.248-16.379 0-22.627l-22.627-22.627c-6.248-6.249-16.379-6.249-22.628 0L216 308.118l-70.059-70.059c-6.248-6.248-16.379-6.248-22.628 0l-22.627 22.627c-6.248 6.248-6.248 16.379 0 22.627l104 104c6.249 6.249 16.379 6.249 22.628.001z" fill="currentColor"></path></svg></span>
</div>
</div>
</fieldset>
</date-selector>
</div>
</div>
<div class="form-row">
<div class="usa-input-error-message form-has-errors">
<p :key="error" v-for="error in popErrors" v-html="error"></p>
</div>
</div>
</div>
<div v-cloak="" v-show="$root.activeModal === removeModalId">
<div :id='"modal--" + removeModalId' class="modal modal--dismissable">
<div class="modal__container">
<div aria-modal="true" class="modal__dialog" role="dialog">
<div class="modal__body">
<div class="task-order__modal-cancel">
<h1 v-html='"Do you want to remove " + clinTitle + "?"'></h1>
<div class="task-order__modal-cancel_buttons">
<button class="usa-button usa-button-primary" type="button" v-on:click="closeModal(removeModalId)">
No, go back
</button>
<button class="usa-button usa-button-primary" type="button" v-on:click="removeClin()">
Yes, remove CLIN
</button>
</div>
</div>
<button class="icon-link modal__dismiss" type="button" v-on:click="closeModal(removeModalId)">
<span aria-hidden="true" class="icon icon--x"><svg viewbox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M2 2l12 12M14 15c-.256 0-.512-.098-.707-.293l-12-12c-.391-.391-.391-1.023 0-1.414s1.023-.391 1.414 0l12 12c.391.391.391 1.023 0 1.414-.195.195-.451.293-.707.293zm0-13L2 14"></path><path d="M2 15c-.256 0-.512-.098-.707-.293-.391-.391-.391-1.023 0-1.414l12-12c.391-.391 1.023-.391 1.414 0s.391 1.023 0 1.414l-12 12C2.512 14.902 2.256 15 2 15z"></path></svg>
</span>
<span>
Close
</span>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</clin-fields>
</div>
<button class="icon-link icon-link__add-another-clin" id="add-clin" type="button" v-on:click="addClin">
<span aria-hidden="true" class="icon icon--plus"><?xml version="1.0" encoding="UTF-8"?>
<svg height="16px" version="1.1" viewbox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 55.2 (78181) - https://sketchapp.com -->
<title>UI element / Icons / Plus / White</title>
<desc>Created with Sketch.</desc>
<g fill="none" fill-rule="evenodd" id="Wizard_Services" stroke="none" stroke-width="1">
<g fill="#0071BC" id="c5-Add-Services" transform="translate(-285.000000, -1059.000000)">
<g id="Group-3" transform="translate(285.000000, 1035.000000)">
<g id="Group-2" transform="translate(0.000000, 21.000000)">
<g id="UI-element-/-Icons-/-Plus-/-White" transform="translate(0.000000, 3.000000)">
<g id="Group">
<path d="M8,16 C3.589,16 0,12.411 0,8 C0,3.589 3.589,0 8,0 C12.411,0 16,3.589 16,8 C16,12.411 12.411,16 8,16 Z M8,2 C4.691,2 2,4.691 2,8 C2,11.309 4.691,14 8,14 C11.309,14 14,11.309 14,8 C14,4.691 11.309,2 8,2 Z" id="Style"></path>
<path d="M8,12 C7.448,12 7,11.4891429 7,10.8571429 L7,5.14285714 C7,4.512 7.448,4 8,4 C8.552,4 9,4.512 9,5.14285714 L9,10.8571429 C9,11.4891429 8.552,12 8,12 Z" id="Path"></path>
<path d="M8,12 C7.448,12 7,11.4891429 7,10.8571429 L7,5.14285714 C7,4.512 7.448,4 8,4 C8.552,4 9,4.512 9,5.14285714 L9,10.8571429 C9,11.4891429 8.552,12 8,12 Z" id="Path" transform="translate(8.000000, 8.000000) rotate(-270.000000) translate(-8.000000, -8.000000) "></path>
</g>
</g>
</g>
</g>
</g>
</g>
</svg></span>
<span>Add another CLIN</span>
</button>
</div>
</div>
</form>
</to-form>

View File

@ -18,7 +18,9 @@
</div>
<div v-show="hasAttachment === false" v-bind:class='{ "usa-input": true, "usa-input--error": showErrors }'>
<p>
</p>
<div v-if="!hideInput" class="upload-widget">
<label class="upload-label" for="pdf">
<span class="upload-button">

View File

@ -19,7 +19,9 @@
</div>
<div v-show="hasAttachment === false" v-bind:class='{ "usa-input": true, "usa-input--error": showErrors }'>
<p>
</p>
<div v-if="!hideInput" class="upload-widget">
<label class="upload-label" for="pdf">
<span class="upload-button">

View File

@ -340,6 +340,7 @@
</div>
<button
id="add-clin"
class="icon-link icon-link__add-another-clin"
v-on:click="addClin"
type="button">

View File

@ -1,10 +1,18 @@
import pytest
from bs4 import BeautifulSoup
from wtforms.widgets import CheckboxInput
from wtforms.fields import StringField
from wtforms.validators import InputRequired, URL
from wtforms.validators import InputRequired
from wtforms import Form, FormField
from atst.forms.task_order import TaskOrderForm
from atst.models import Permissions
from atst.routes.task_orders.new import render_task_orders_edit
from atst.utils.context_processors import user_can_view
from tests import factories
class InitialValueForm(Form):
datafield = StringField(label="initialvalue value", default="initialvalue")
@ -82,3 +90,35 @@ def test_make_upload_input_error_template(upload_input_macro, task_order_form):
task_order_form.validate()
rendered_upload_macro = upload_input_macro(task_order_form.pdf)
write_template(rendered_upload_macro, "upload_input_error_template.html")
def test_make_task_order_step3_template(app, request_ctx):
request_ctx.g.current_user = factories.UserFactory.create()
request_ctx.g.application = None
request_ctx.g.portfolio = None
# hard-code the portfolio ID so it does not change the fragment every time
# this is run
portfolio = factories.PortfolioFactory.create(
id="e4edf994-04f4-4aaa-ba30-39507e1068a8"
)
# hard-code the TO number for the same reason
task_order = factories.TaskOrderFactory.create(
portfolio=portfolio, number="1234567890123"
)
task_order_form = TaskOrderForm(obj=task_order)
step3 = render_task_orders_edit(
"task_orders/step_3.html",
form=task_order_form,
portfolio_id=task_order.portfolio_id,
extra_args={
"portfolio": task_order.portfolio,
"permissions": Permissions,
"user_can": user_can_view,
"task_order": task_order,
"contract_start": app.config.get("CONTRACT_START_DATE"),
"contract_end": app.config.get("CONTRACT_END_DATE"),
},
)
dom = BeautifulSoup(step3, "html.parser")
to_form = dom.find("to-form")
write_template(str(to_form), "to_form.html")