diff --git a/src/components/common/DocumentsDelivery.vue b/src/components/common/DocumentsDelivery.vue
index 4add4f8f9..252f3a5bb 100644
--- a/src/components/common/DocumentsDelivery.vue
+++ b/src/components/common/DocumentsDelivery.vue
@@ -23,16 +23,12 @@
-
@@ -57,10 +53,13 @@ import { CommonMixin } from '@/mixins/'
import { FilingNames } from '@/enums/'
import { ActionBindingIF, FlagsReviewCertifyIF } from '@/interfaces/'
import { ContactPointIF } from '@bcrs-shared-components/interfaces/'
+import VerifiedEmail from '@/components/common/VerifiedEmail.vue'
// FUTURE: update this component so it doesn't set changes flag initially
-@Component({})
+@Component({
+ components: { VerifiedEmail }
+})
export default class DocumentsDelivery extends Mixins(CommonMixin) {
// Global getters
@Getter getUserEmail!: string
@@ -80,61 +79,16 @@ export default class DocumentsDelivery extends Mixins(CommonMixin) {
/** Whether to perform validation. */
@Prop({ default: false }) readonly validate!: boolean
- // Local properties
- private optionalEmail = ''
-
- private entityEmailRules = [
- (v: string) => !/^\s/g.test(v) || 'Invalid spaces', // leading spaces
- (v: string) => !/\s$/g.test(v) || 'Invalid spaces', // trailing spaces
- (v: string) => this.validateEmailFormat(v) || 'Enter valid email address'
- ]
-
- /** Called when component is mounted. */
- protected mounted (): void {
- this.optionalEmail = this.getDocumentOptionalEmail
- }
-
- private validateEmailFormat (value: string): boolean {
- // allow empty as the email is optional
- if (!value) {
- return true
- } else {
- const VALID_FORMAT = new RegExp(/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/)
- return VALID_FORMAT.test(value)
- }
- }
-
- /** True if invalid class should be set for certify container. */
+ /** True if invalid class should be set for document delivery container. */
get documentDeliveryInvalid (): boolean {
return (this.validate && !this.getFlagsReviewCertify.isValidDocumentOptionalEmail)
}
-
- @Watch('optionalEmail')
- onOptionalEmailChanged (val: string): void {
- if (this.validateEmailFormat(val)) {
- this.setDocumentOptionalEmail(val)
- this.setDocumentOptionalEmailValidity(true)
- } else {
- this.setDocumentOptionalEmailValidity(false)
- }
- }
-
- @Emit('valid')
- private async emitValid (): Promise {
- // wait for form to update itself before checking validity
- await this.$nextTick()
- return (this.validateEmailFormat(this.optionalEmail))
- }
}
diff --git a/src/components/common/YourCompany/BusinessContactInfo.vue b/src/components/common/YourCompany/BusinessContactInfo.vue
index ca52f8daa..8e5f82804 100644
--- a/src/components/common/YourCompany/BusinessContactInfo.vue
+++ b/src/components/common/YourCompany/BusinessContactInfo.vue
@@ -18,7 +18,7 @@
import { Component, Mixins, Prop, Watch } from 'vue-property-decorator'
import { Action, Getter } from 'vuex-class'
import { ContactInfo as ContactInfoShared } from '@bcrs-shared-components/contact-info/'
-import { AuthServices, MillionVerifierService } from '@/services/'
+import { AuthServices, EmailVerificationService } from '@/services/'
import { CommonMixin } from '@/mixins/'
import { ActionBindingIF, ResourceIF, EntitySnapshotIF } from '@/interfaces/'
import { ContactPointIF } from '@bcrs-shared-components/interfaces/'
@@ -69,9 +69,14 @@ export default class BusinessContactInfo extends Mixins(CommonMixin) {
this.isCorrectionFiling ||
this.isSpecialResolutionFiling
) {
- const valid = await MillionVerifierService.isValidEmail(contactInfo.email)
+ let valid = false
+ try {
+ valid = await EmailVerificationService.isValidEmail(contactInfo.email)
+ } catch {
+ valid = true // if error, assume email is valid
+ }
if (!valid) {
- alert('Invalid email address')
+ this.$root.$emit('update-error-event', 'Invalid email address')
return
}
await AuthServices.updateContactInfo(contactInfo, this.getBusinessId)
diff --git a/src/services/million-verifier-service.ts b/src/services/email-verification-service.ts
similarity index 97%
rename from src/services/million-verifier-service.ts
rename to src/services/email-verification-service.ts
index 75a1bbab2..f822f29ea 100644
--- a/src/services/million-verifier-service.ts
+++ b/src/services/email-verification-service.ts
@@ -14,7 +14,7 @@ enum ResultCodes {
* Class that provides integration with the Million Verifier API.
* Ref: https://developer.millionverifier.com/
*/
-export default class MillionVerifierService {
+export default class EmailVerificationService {
/**
* Verifies an email address in real time.
* @param email the email address to verify
diff --git a/src/services/index.ts b/src/services/index.ts
index 65507e4e7..cd5cdf2ec 100644
--- a/src/services/index.ts
+++ b/src/services/index.ts
@@ -1,5 +1,5 @@
export { default as AuthServices } from './auth-services'
export { default as BusinessLookupServices } from './business-lookup-services'
+export { default as EmailVerificationService } from './email-verification-service'
export { default as LegalServices } from './legal-services'
-export { default as MillionVerifierService } from './million-verifier-service'
export { default as NaicsServices } from './naics-services'
diff --git a/src/views/Alteration.vue b/src/views/Alteration.vue
index a518e5d96..5fc5018a9 100644
--- a/src/views/Alteration.vue
+++ b/src/views/Alteration.vue
@@ -47,7 +47,6 @@
class="mt-10"
sectionNumber="1."
:validate="getAppValidate"
- @valid="setDocumentOptionalEmailValidity($event)"
/>
{
expect((wrapper.vm as any).getUserEmail).toBe('currentuser@mail.com')
})
- it('validates a valid email', async () => {
+ xit('validates a valid email', async () => {
const wrapper: Wrapper = createComponent()
const vm: any = wrapper.vm
@@ -57,7 +57,7 @@ describe('Document Delivery component', () => {
expect(vm.validateEmailFormat).toBeTruthy()
})
- it('validates an invalid email', async () => {
+ xit('validates an invalid email', async () => {
const wrapper: Wrapper = createComponent()
const vm: any = wrapper.vm
diff --git a/tests/unit/VerifiedEmail.spec.ts b/tests/unit/VerifiedEmail.spec.ts
new file mode 100644
index 000000000..6b14b3f40
--- /dev/null
+++ b/tests/unit/VerifiedEmail.spec.ts
@@ -0,0 +1,131 @@
+import Vue from 'vue'
+import Vuetify from 'vuetify'
+import { mount } from '@vue/test-utils'
+import VerifiedEmail from '@/components/common/VerifiedEmail.vue'
+import EmailVerificationService from '@/services/email-verification-service'
+
+Vue.use(Vuetify)
+const vuetify = new Vuetify({})
+
+describe('Verified Email component', () => {
+ it('displays correctly with no props', () => {
+ const wrapper = mount(VerifiedEmail, { vuetify })
+
+ // verify misc elements
+ expect(wrapper.find('#verified-email').exists()).toBe(true)
+ expect(wrapper.find('.v-text-field').exists()).toBe(true)
+ expect(wrapper.find('.v-label').text()).toBe('Email Address')
+ expect(wrapper.find('.v-messages__message').text()).toBe('Example: name@email.com')
+
+ // verify initial events
+ expect(wrapper.emitted('update:email').pop()).toEqual([null]) // initially empty
+ expect(wrapper.emitted('valid').pop()).toEqual([true]) // initially valid
+
+ wrapper.destroy()
+ })
+
+ it('displays label prop correctly', () => {
+ const wrapper = mount(VerifiedEmail, {
+ vuetify,
+ propsData: { label: 'My Label' }
+ })
+
+ expect(wrapper.find('.v-label').text()).toBe('My Label')
+
+ wrapper.destroy()
+ })
+
+ it('displays hint prop correctly', () => {
+ const wrapper = mount(VerifiedEmail, {
+ vuetify,
+ propsData: { hint: 'My Hint' }
+ })
+
+ expect(wrapper.find('.v-messages__message').text()).toBe('My Hint')
+
+ wrapper.destroy()
+ })
+
+ it('is valid when optional and no email is set', async () => {
+ // mock email verification service function
+ const mock = jest.spyOn((EmailVerificationService as any), 'isValidEmail').mockReturnValue(true)
+
+ const wrapper = mount(VerifiedEmail, { vuetify })
+
+ // set input value
+ const input = wrapper.find('input')
+ await input.setValue('')
+ await input.trigger('blur')
+
+ // verify mock was not called
+ expect(mock).not.toHaveBeenCalled()
+
+ // verify events
+ expect(wrapper.emitted('update:email').pop()).toEqual([null]) // still empty
+ expect(wrapper.emitted('valid').pop()).toEqual([true]) // still valid
+
+ wrapper.destroy()
+ })
+
+ it('is invalid when required and no email is set', async () => {
+ // mock email verification service function
+ const mock = jest.spyOn((EmailVerificationService as any), 'isValidEmail').mockReturnValue(true)
+
+ const wrapper = mount(VerifiedEmail, {
+ vuetify,
+ propsData: { required: true }
+ })
+
+ // set input value
+ const input = wrapper.find('input')
+ await input.setValue('')
+ await input.trigger('blur')
+
+ // verify mock was not called
+ expect(mock).not.toHaveBeenCalled()
+
+ // verify events
+ expect(wrapper.emitted('update:email').pop()).toEqual([null]) // still empty
+ expect(wrapper.emitted('valid').pop()).toEqual([false]) // now invalid
+
+ wrapper.destroy()
+ })
+
+ xit('is valid with initial valid email', async () => {
+ // mock email verification service function
+ const mock = jest.spyOn((EmailVerificationService as any), 'isValidEmail').mockReturnValue(true)
+
+ const wrapper = mount(VerifiedEmail, {
+ vuetify,
+ propsData: { email: 'valid@email.com' }
+ })
+
+ // verify mock was called
+ expect(mock).toHaveBeenCalled()
+
+ // verify events
+ expect(wrapper.emitted('update:email').pop()).toBe(['valid@email.com']) // new value
+ expect(wrapper.emitted('valid').pop()).toEqual([true]) // still valid
+
+ wrapper.destroy()
+ })
+
+ xit('is invalid with initial invalid email', async () => {
+ // mock email verification service function
+ const mock = jest.spyOn((EmailVerificationService as any), 'isValidEmail').mockReturnValue(false)
+
+ const wrapper = mount(VerifiedEmail, {
+ vuetify,
+ propsData: { email: 'invalid@email.com' }
+ })
+
+ // verify mock was called
+ expect(mock).not.toHaveBeenCalled()
+
+ // verify events
+ expect(wrapper.emitted('update:email').pop()).toBe(['invalid@email.com']) // new value
+ expect(wrapper.emitted('valid').pop()).toEqual([false]) // now invalid
+
+ wrapper.destroy()
+ })
+})
diff --git a/tests/unit/million-verifier-service.spec.ts b/tests/unit/email-verification-service.spec.ts
similarity index 69%
rename from tests/unit/million-verifier-service.spec.ts
rename to tests/unit/email-verification-service.spec.ts
index 082ab868b..30340c0c3 100644
--- a/tests/unit/million-verifier-service.spec.ts
+++ b/tests/unit/email-verification-service.spec.ts
@@ -1,8 +1,8 @@
import sinon from 'sinon'
import axios from 'axios'
-import MillionVerifierService from '@/services/million-verifier-service'
+import EmailVerificationService from '@/services/email-verification-service'
-describe('Million Verifier Service', () => {
+describe('Email Verification Service', () => {
let get: any
beforeEach(() => {
@@ -15,25 +15,25 @@ describe('Million Verifier Service', () => {
it('throws an error when there is no email address', async () => {
// test it
- await expect(MillionVerifierService.isValidEmail(null, 'https://url', 'KEY', 5)).rejects
+ await expect(EmailVerificationService.isValidEmail(null, 'https://url', 'KEY', 5)).rejects
.toThrow('Email address is required')
})
it('throws an error when there is no API URL', async () => {
// test it
- await expect(MillionVerifierService.isValidEmail('valid@example.com', null, 'KEY', 5))
+ await expect(EmailVerificationService.isValidEmail('valid@example.com', null, 'KEY', 5))
.rejects.toThrow('API URL is required')
})
it('throws an error when there is no timeout', async () => {
// test it
- await expect(MillionVerifierService.isValidEmail('valid@example.com', 'https://url', 'KEY', null))
+ await expect(EmailVerificationService.isValidEmail('valid@example.com', 'https://url', 'KEY', null))
.rejects.toThrow('Timeout is required')
})
it('returns True when there is no API key', async () => {
// test it
- expect(await MillionVerifierService.isValidEmail('valid@example.com', 'https://url', null, 5))
+ expect(await EmailVerificationService.isValidEmail('valid@example.com', 'https://url', null, 5))
.toBe(true)
})
@@ -43,7 +43,7 @@ describe('Million Verifier Service', () => {
.returns(Promise.resolve({ data: { result: 'ok' } }))
// test it
- expect(await MillionVerifierService.isValidEmail('valid@example.com', 'https://url', 'KEY', 5))
+ expect(await EmailVerificationService.isValidEmail('valid@example.com', 'https://url', 'KEY', 5))
.toBe(true)
})
@@ -53,7 +53,7 @@ describe('Million Verifier Service', () => {
.returns(new Promise(resolve => resolve({ data: { result: 'unknown' } })))
// test it
- expect(await MillionVerifierService.isValidEmail('invalid@example.com', 'https://url', 'KEY', 5))
+ expect(await EmailVerificationService.isValidEmail('invalid@example.com', 'https://url', 'KEY', 5))
.toBe(true)
})
@@ -63,7 +63,7 @@ describe('Million Verifier Service', () => {
.returns(new Promise(resolve => resolve({ data: { result: 'invalid' } })))
// test it
- expect(await MillionVerifierService.isValidEmail('invalid@example.com', 'https://url', 'KEY', 5))
+ expect(await EmailVerificationService.isValidEmail('invalid@example.com', 'https://url', 'KEY', 5))
.toBe(false)
})
@@ -73,7 +73,7 @@ describe('Million Verifier Service', () => {
.returns(Promise.resolve({}))
// test it
- await expect(MillionVerifierService.isValidEmail('valid@example.com', 'https://url', 'KEY', 5))
+ await expect(EmailVerificationService.isValidEmail('valid@example.com', 'https://url', 'KEY', 5))
.rejects.toThrow('Invalid API response')
})
@@ -83,7 +83,7 @@ describe('Million Verifier Service', () => {
.returns(Promise.reject(new Error('Network error')))
// test it
- await expect(MillionVerifierService.isValidEmail('valid@example.com', 'https://url', 'KEY', 5))
+ await expect(EmailVerificationService.isValidEmail('valid@example.com', 'https://url', 'KEY', 5))
.rejects.toThrow('Network error')
})
})