From 6e0bb051f12b37c895044f080131864ac3643fd7 Mon Sep 17 00:00:00 2001 From: John Sandoval Date: Wed, 2 Sep 2026 14:01:04 -0600 Subject: [PATCH 1/2] WIP: social work search updates --- .../LicenseeList/LicenseeList.spec.ts | 57 ++++- .../Licensee/LicenseeList/LicenseeList.ts | 20 ++ .../LicenseeSearch/LicenseeSearch.spec.ts | 88 ++++++- .../Licensee/LicenseeSearch/LicenseeSearch.ts | 31 +++ .../LicenseeSearch/LicenseeSearch.vue | 6 + .../LicenseeSearchLegacy.ts | 2 +- webroot/src/locales/en.json | 1 + webroot/src/locales/es.json | 1 + .../models/Licensee/Licensee.model.spec.ts | 214 ++++++++++++++++++ webroot/src/models/Licensee/Licensee.model.ts | 6 + webroot/src/network/searchApi/data.api.ts | 15 ++ .../src/store/license/license.mutations.ts | 10 +- webroot/src/store/license/license.spec.ts | 24 ++ 13 files changed, 467 insertions(+), 8 deletions(-) diff --git a/webroot/src/components/Licensee/LicenseeList/LicenseeList.spec.ts b/webroot/src/components/Licensee/LicenseeList/LicenseeList.spec.ts index c7a67eff75..333ebc1102 100644 --- a/webroot/src/components/Licensee/LicenseeList/LicenseeList.spec.ts +++ b/webroot/src/components/Licensee/LicenseeList/LicenseeList.spec.ts @@ -5,15 +5,70 @@ // Created by InspiringApps on 12/1/2025. // -import { expect } from 'chai'; +import chaiMatchPattern from 'chai-match-pattern'; +import chai from 'chai'; import { mountShallow } from '@tests/helpers/setup'; import LicenseeList from '@components/Licensee/LicenseeList/LicenseeList.vue'; +import { Compact, CompactType } from '@models/Compact/Compact.model'; +import { AppModes } from '@/app.config'; +import store from '@store/index'; + +chai.use(chaiMatchPattern); + +const { expect } = chai; describe('LicenseeList component', async () => { + afterEach(async () => { + await store.dispatch('setAppMode', AppModes.JCC); + await store.dispatch('user/setCurrentCompact', null); + await store.dispatch('license/resetStoreSearch'); + }); + it('should mount the component', async () => { const wrapper = await mountShallow(LicenseeList); expect(wrapper.exists()).to.equal(true); expect(wrapper.findComponent(LicenseeList).exists()).to.equal(true); }); + it('should successfully prepare search params including license scope', async () => { + const wrapper = await mountShallow(LicenseeList); + const component = wrapper.vm; + + await component.$store.dispatch('setAppMode', AppModes.SOCIAL_WORK); + await component.$store.dispatch('user/setCurrentCompact', new Compact({ type: CompactType.SOCIAL_WORK })); + await component.$store.dispatch('license/setStoreSearch', { + homeState: 'co', + licenseScope: 'multi-state', + }); + + const requestConfig = component.prepareSearchBody(); + + expect(requestConfig).to.matchPattern({ + compact: CompactType.SOCIAL_WORK, + homeState: 'co', + licenseScope: 'multi-state', + '...': '', + }); + }); + it('should successfully display license scope in the search tag', async () => { + const wrapper = await mountShallow(LicenseeList); + const component = wrapper.vm; + + await component.$store.dispatch('setAppMode', AppModes.SOCIAL_WORK); + await component.$store.dispatch('license/setStoreSearch', { + firstName: 'Test', + lastName: 'User', + homeState: 'co', + licenseScope: 'multi-state', + }); + + expect(component.searchDisplayLicenseScope).to.equal( + `${component.$t('licensing.licenseScope')}: Multi state` + ); + expect(component.searchDisplayAll).to.equal([ + 'Test User', + component.searchDisplayHomeState, + component.searchDisplayLicenseScope, + ].join(', ')); + }); }); diff --git a/webroot/src/components/Licensee/LicenseeList/LicenseeList.ts b/webroot/src/components/Licensee/LicenseeList/LicenseeList.ts index 21e284bcdd..ede1d6b6bf 100644 --- a/webroot/src/components/Licensee/LicenseeList/LicenseeList.ts +++ b/webroot/src/components/Licensee/LicenseeList/LicenseeList.ts @@ -115,6 +115,22 @@ class LicenseeList extends Vue { return (homeState) ? `${this.$t('licensing.homeState')}: ${new State({ abbrev: homeState }).name()}` : ''; } + get searchDisplayLicenseScope(): string { + const { licenseScope } = this.searchParams; + let displayScope = ''; + + if (licenseScope) { + const scopeOptions = this.$tm('licensing.licenseScopes') || []; + const selectedOption = scopeOptions.find((scopeOption) => scopeOption.key === licenseScope); + + if (selectedOption?.name) { + displayScope = `${this.$t('licensing.licenseScope')}: ${selectedOption.name}`; + } + } + + return displayScope; + } + get searchDisplayPrivilegeState(): string { const { privilegeState } = this.searchParams; @@ -207,6 +223,7 @@ class LicenseeList extends Vue { this.searchDisplayFullName, this.searchDisplayDob, this.searchDisplayHomeState, + this.searchDisplayLicenseScope, this.searchDisplayPrivilegeState, this.searchDisplayPrivilegePurchaseDates, this.searchDisplayMilitaryStatus, @@ -384,6 +401,9 @@ class LicenseeList extends Vue { if (searchParams?.homeState) { requestConfig.homeState = searchParams.homeState.toLowerCase(); } + if (searchParams?.licenseScope) { + requestConfig.licenseScope = searchParams.licenseScope; + } if (searchParams?.privilegeState) { requestConfig.privilegeState = searchParams.privilegeState.toLowerCase(); } diff --git a/webroot/src/components/Licensee/LicenseeSearch/LicenseeSearch.spec.ts b/webroot/src/components/Licensee/LicenseeSearch/LicenseeSearch.spec.ts index be614bd50a..f820b38019 100644 --- a/webroot/src/components/Licensee/LicenseeSearch/LicenseeSearch.spec.ts +++ b/webroot/src/components/Licensee/LicenseeSearch/LicenseeSearch.spec.ts @@ -5,15 +5,101 @@ // Created by InspiringApps on 12/1/2025. // -import { expect } from 'chai'; +import chaiMatchPattern from 'chai-match-pattern'; +import chai from 'chai'; import { mountShallow } from '@tests/helpers/setup'; import LicenseeSearch from '@components/Licensee/LicenseeSearch/LicenseeSearch.vue'; +import { Compact, CompactType } from '@models/Compact/Compact.model'; +import { AppModes } from '@/app.config'; +import store from '@store/index'; + +chai.use(chaiMatchPattern); + +const { expect } = chai; describe('LicenseeSearch component', async () => { + afterEach(async () => { + await store.dispatch('setAppMode', AppModes.JCC); + await store.dispatch('user/setCurrentCompact', null); + }); + it('should mount the component', async () => { const wrapper = await mountShallow(LicenseeSearch); expect(wrapper.exists()).to.equal(true); expect(wrapper.findComponent(LicenseeSearch).exists()).to.equal(true); }); + it('should successfully emit searchParams for social work staff search', async () => { + await store.dispatch('setAppMode', AppModes.SOCIAL_WORK); + + let emittedSearchParams; + const wrapper = await mountShallow(LicenseeSearch, { + props: { + onSearchParams: (searchParams) => { + emittedSearchParams = searchParams; + }, + }, + }); + const { formData } = wrapper.vm; + + formData.homeState.value = 'co'; + formData.licenseScope.value = 'multi-state'; + await wrapper.vm.handleSubmit(); + + expect(emittedSearchParams).to.matchPattern({ + homeState: 'co', + licenseScope: 'multi-state', + '...': '', + }); + }); + it('should successfully omit licenseScope from searchParams for social work public search', async () => { + await store.dispatch('setAppMode', AppModes.SOCIAL_WORK); + await store.dispatch('user/setCurrentCompact', new Compact({ type: CompactType.SOCIAL_WORK })); + + let emittedSearchParams; + const wrapper = await mountShallow(LicenseeSearch, { + props: { + isPublicSearch: true, + onSearchParams: (searchParams) => { + emittedSearchParams = searchParams; + }, + }, + }); + const { formData } = wrapper.vm; + + formData.compact.value = CompactType.SOCIAL_WORK; + formData.homeState.value = 'co'; + formData.licenseScope.value = 'multi-state'; + await wrapper.vm.handleSubmit(); + + expect(emittedSearchParams).to.matchPattern({ + compact: CompactType.SOCIAL_WORK, + homeState: 'co', + licenseScope: undefined, + '...': '', + }); + }); + it('should successfully omit licenseScope from searchParams for cosmetology staff search', async () => { + await store.dispatch('setAppMode', AppModes.COSMETOLOGY); + + let emittedSearchParams; + const wrapper = await mountShallow(LicenseeSearch, { + props: { + onSearchParams: (searchParams) => { + emittedSearchParams = searchParams; + }, + }, + }); + const { formData } = wrapper.vm; + + formData.homeState.value = 'co'; + formData.licenseScope.value = 'multi-state'; + await wrapper.vm.handleSubmit(); + + expect(emittedSearchParams).to.matchPattern({ + homeState: 'co', + licenseScope: undefined, + '...': '', + }); + }); }); diff --git a/webroot/src/components/Licensee/LicenseeSearch/LicenseeSearch.ts b/webroot/src/components/Licensee/LicenseeSearch/LicenseeSearch.ts index 4f336dafac..873ff80a8b 100644 --- a/webroot/src/components/Licensee/LicenseeSearch/LicenseeSearch.ts +++ b/webroot/src/components/Licensee/LicenseeSearch/LicenseeSearch.ts @@ -45,6 +45,7 @@ export interface LicenseSearch { firstName?: string; lastName?: string; homeState?: string; + licenseScope?: string; dob?: string; privilegeState?: string; privilegePurchaseStartDate?: string; @@ -177,6 +178,20 @@ class LicenseeSearch extends mixins(MixinForm) { return options; } + get licenseScopeOptions(): Array<{ value: string, name: string | ComputedRef }> { + const options = this.$tm('licensing.licenseScopes').map((option) => ({ + value: option.key, + name: option.name, + })); + + options.unshift({ + value: '', + name: computed(() => this.$t('common.selectOption')), + }); + + return options; + } + get investigationStatusOptions(): Array<{ value: string, name: string | ComputedRef }> { const options = this.$tm('licensing.investigationStatusOptions').map((option) => ({ value: option.key, @@ -243,6 +258,13 @@ class LicenseeSearch extends mixins(MixinForm) { value: this.searchParams.homeState || '', isDisabled: computed(() => this.enableCompactSelect && !this.compactType), }), + licenseScope: new FormInput({ + id: 'license-scope', + name: 'license-scope', + label: computed(() => this.$t('licensing.licenseScope')), + valueOptions: this.licenseScopeOptions, + value: this.searchParams.licenseScope || '', + }), licenseNumber: new FormInput({ id: 'license-number', name: 'license-number', @@ -384,6 +406,10 @@ class LicenseeSearch extends mixins(MixinForm) { allowedSearchProps.push('dob'); } + if (this.$isAppModeSocialWork && !this.isPublicSearch) { + allowedSearchProps.push('licenseScope'); + } + allowedSearchProps.forEach((searchProp) => { searchProps[searchProp] = this.formValues[searchProp]; }); this.$emit('searchParams', searchProps); @@ -403,6 +429,7 @@ class LicenseeSearch extends mixins(MixinForm) { this.formData.encumberStartDate.value = ''; this.formData.encumberEndDate.value = ''; this.formData.npi.value = ''; + this.formData.licenseScope.value = ''; this.formData.licenseNumber.value = ''; this.formData.dob.value = ''; this.isFormLoading = false; @@ -431,6 +458,10 @@ class LicenseeSearch extends mixins(MixinForm) { this.formData.dob.value = moment('1970-01-01').format('YYYY-MM-DD'); } + if (this.$isAppModeSocialWork && !this.isPublicSearch) { + this.formData.licenseScope.value = 'multi-state'; + } + this.validateAll({ asTouched: true }); await nextTick(); const submitButton = document.getElementById('submit'); diff --git a/webroot/src/components/Licensee/LicenseeSearch/LicenseeSearch.vue b/webroot/src/components/Licensee/LicenseeSearch/LicenseeSearch.vue index 46e8c7f805..023b5a38ba 100644 --- a/webroot/src/components/Licensee/LicenseeSearch/LicenseeSearch.vue +++ b/webroot/src/components/Licensee/LicenseeSearch/LicenseeSearch.vue @@ -60,6 +60,12 @@ :title="(formData.homeState.isDisabled) ? $t('licensing.searchStateDisabled') : ''" /> +
+ +
{ // Test hasEncumbranceLiftedWithinWaitPeriod method expect(licensee.hasEncumbranceLiftedWithinWaitPeriod()).to.equal(true); }); + it('should create a Licensee with adverse actions built from license & privilege data', () => { + const data = { + providerId: 'test-id', + licenseJurisdiction: 'co', + currentHomeJurisdiction: 'co', + licenseType: LicenseType.AUDIOLOGIST, + licenseStatus: LicenseeStatus.ACTIVE, + licenses: [ + { + providerId: 'test-id', + compact: CompactType.ASLP, + type: 'license-home', + jurisdiction: 'co', + licenseType: LicenseType.AUDIOLOGIST, + licenseStatus: LicenseStatus.ACTIVE, + compactEligibility: EligibilityStatus.ELIGIBLE, + adverseActions: [ + { + adverseActionId: 'test-license-adverseAction-id', + providerId: 'test-id', + compact: CompactType.ASLP, + type: 'adverseAction', + encumbranceType: 'fine', + clinicalPrivilegeActionCategories: ['Non-compliance With Requirements'], + actionAgainst: 'license', + jurisdiction: 'co', + creationDate: moment().subtract(1, 'week').format(serverDatetimeFormat), + effectiveStartDate: moment().subtract(1, 'month').format(serverDateFormat), + effectiveLiftDate: moment().add(11, 'months').format(serverDateFormat), + }, + ], + }, + ], + privilegeJurisdictions: ['al'], + privileges: [ + { + providerId: 'test-id', + compact: CompactType.ASLP, + type: 'privilege', + jurisdiction: 'al', + licenseType: LicenseType.AUDIOLOGIST, + status: LicenseStatus.ACTIVE, + adverseActions: [ + { + adverseActionId: 'test-privilege-adverseAction-id', + providerId: 'test-id', + compact: CompactType.ASLP, + type: 'adverseAction', + encumbranceType: 'suspension', + clinicalPrivilegeActionCategories: ['Unsafe Practice or Substandard Care'], + actionAgainst: 'privilege', + jurisdiction: 'al', + creationDate: moment().subtract(8, 'months').format(serverDatetimeFormat), + effectiveStartDate: moment().subtract(7, 'months').format(serverDateFormat), + effectiveLiftDate: moment().subtract(5, 'months').format(serverDateFormat), + }, + ], + }, + ], + }; + const licensee = LicenseeSerializer.fromServer(data); + const serverLicenseAction = data.licenses[0].adverseActions[0]; + const serverPrivilegeAction = data.privileges[0].adverseActions[0]; + + // Test field values; license adverse actions are listed ahead of privilege adverse actions + expect(licensee.adverseActions).to.be.an('array').with.length(2); + expect(licensee.adverseActions[0]).to.be.an.instanceof(AdverseAction); + expect(licensee.adverseActions[0].id).to.equal(serverLicenseAction.adverseActionId); + expect(licensee.adverseActions[0].state?.abbrev).to.equal(serverLicenseAction.jurisdiction); + expect(licensee.adverseActions[0].startDate).to.equal(serverLicenseAction.effectiveStartDate); + expect(licensee.adverseActions[0].endDate).to.equal(serverLicenseAction.effectiveLiftDate); + expect(licensee.adverseActions[1]).to.be.an.instanceof(AdverseAction); + expect(licensee.adverseActions[1].id).to.equal(serverPrivilegeAction.adverseActionId); + expect(licensee.adverseActions[1].state?.abbrev).to.equal(serverPrivilegeAction.jurisdiction); + expect(licensee.adverseActions[1].startDate).to.equal(serverPrivilegeAction.effectiveStartDate); + expect(licensee.adverseActions[1].endDate).to.equal(serverPrivilegeAction.effectiveLiftDate); + + // Test methods + expect(licensee.hasEncumberedLicenses()).to.equal(true); + expect(licensee.hasEncumberedPrivileges()).to.equal(false); + expect(licensee.isEncumbered()).to.equal(true); + }); + it('should create a Licensee with adverse actions built from license data only', () => { + const data = { + providerId: 'test-id', + licenses: [ + { + providerId: 'test-id', + type: 'license-home', + jurisdiction: 'co', + licenseType: LicenseType.AUDIOLOGIST, + adverseActions: [{ adverseActionId: 'test-license-adverseAction-id', jurisdiction: 'co' }], + }, + ], + }; + const licensee = LicenseeSerializer.fromServer(data); + + expect(licensee.adverseActions).to.be.an('array').with.length(1); + expect(licensee.adverseActions[0].id).to.equal('test-license-adverseAction-id'); + }); + it('should create a Licensee with adverse actions built from privilege data only', () => { + const data = { + providerId: 'test-id', + privileges: [ + { + providerId: 'test-id', + type: 'privilege', + jurisdiction: 'al', + licenseType: LicenseType.AUDIOLOGIST, + adverseActions: [{ adverseActionId: 'test-privilege-adverseAction-id', jurisdiction: 'al' }], + }, + ], + }; + const licensee = LicenseeSerializer.fromServer(data); + + expect(licensee.adverseActions).to.be.an('array').with.length(1); + expect(licensee.adverseActions[0].id).to.equal('test-privilege-adverseAction-id'); + }); + it('should create a Licensee with adverse actions built from license & privilege data (null licensee level)', () => { + const data = { + providerId: 'test-id', + adverseActions: null, + licenses: [ + { + providerId: 'test-id', + type: 'license-home', + jurisdiction: 'co', + licenseType: LicenseType.AUDIOLOGIST, + adverseActions: [{ adverseActionId: 'test-license-adverseAction-id', jurisdiction: 'co' }], + }, + ], + privileges: [ + { + providerId: 'test-id', + type: 'privilege', + jurisdiction: 'al', + licenseType: LicenseType.AUDIOLOGIST, + adverseActions: [{ adverseActionId: 'test-privilege-adverseAction-id', jurisdiction: 'al' }], + }, + ], + }; + const licensee = LicenseeSerializer.fromServer(data); + + expect(licensee.adverseActions).to.be.an('array').with.length(2); + expect(licensee.adverseActions[0].id).to.equal('test-license-adverseAction-id'); + expect(licensee.adverseActions[1].id).to.equal('test-privilege-adverseAction-id'); + }); + it('should create a Licensee with licensee-level adverse actions taking precedence over license & privilege data', () => { + const data = { + providerId: 'test-id', + adverseActions: [{ adverseActionId: 'test-licensee-adverseAction-id', jurisdiction: 'oh' }], + licenses: [ + { + providerId: 'test-id', + type: 'license-home', + jurisdiction: 'co', + licenseType: LicenseType.AUDIOLOGIST, + adverseActions: [{ adverseActionId: 'test-license-adverseAction-id', jurisdiction: 'co' }], + }, + ], + privileges: [ + { + providerId: 'test-id', + type: 'privilege', + jurisdiction: 'al', + licenseType: LicenseType.AUDIOLOGIST, + adverseActions: [{ adverseActionId: 'test-privilege-adverseAction-id', jurisdiction: 'al' }], + }, + ], + }; + const licensee = LicenseeSerializer.fromServer(data); + + expect(licensee.adverseActions).to.be.an('array').with.length(1); + expect(licensee.adverseActions[0].id).to.equal('test-licensee-adverseAction-id'); + expect(licensee.licenses[0].adverseActions).to.be.an('array').with.length(1); + expect(licensee.privileges[0].adverseActions).to.be.an('array').with.length(1); + }); + it('should create a Licensee with no adverse actions (empty licensee-level array)', () => { + const data = { + providerId: 'test-id', + adverseActions: [], + licenses: [ + { + providerId: 'test-id', + type: 'license-home', + jurisdiction: 'co', + licenseType: LicenseType.AUDIOLOGIST, + adverseActions: [{ adverseActionId: 'test-license-adverseAction-id', jurisdiction: 'co' }], + }, + ], + privileges: [ + { + providerId: 'test-id', + type: 'privilege', + jurisdiction: 'al', + licenseType: LicenseType.AUDIOLOGIST, + adverseActions: [{ adverseActionId: 'test-privilege-adverseAction-id', jurisdiction: 'al' }], + }, + ], + }; + const licensee = LicenseeSerializer.fromServer(data); + + expect(licensee.adverseActions).to.matchPattern([]); + }); + it('should create a Licensee with no adverse actions (get-all response shape)', () => { + const data = { + providerId: 'test-id', + licenseJurisdiction: 'co', + privilegeJurisdictions: ['al'], + }; + const licensee = LicenseeSerializer.fromServer(data); + + expect(licensee.adverseActions).to.matchPattern([]); + }); it('should serialize a Licensee for transmission to server', () => { const licensee = LicenseeSerializer.fromServer({ providerId: 'test-id', diff --git a/webroot/src/models/Licensee/Licensee.model.ts b/webroot/src/models/Licensee/Licensee.model.ts index 488b9a1545..8910e8d0f9 100644 --- a/webroot/src/models/Licensee/Licensee.model.ts +++ b/webroot/src/models/Licensee/Licensee.model.ts @@ -504,6 +504,12 @@ export class LicenseeSerializer { json.adverseActions.forEach((serverAdverseAction) => { licenseeData.adverseActions.push(AdverseActionSerializer.fromServer(serverAdverseAction)); }); + } else { + // If no adverseActions at licensee level, attempt to build adverse actions from license / privilege data + licenseeData.adverseActions = [ + ...licenseeData.licenses.flatMap((license) => license.adverseActions), + ...licenseeData.privileges.flatMap((privilege) => privilege.adverseActions), + ]; } return new Licensee(licenseeData); diff --git a/webroot/src/network/searchApi/data.api.ts b/webroot/src/network/searchApi/data.api.ts index 433a13efa6..f3fbab16b7 100644 --- a/webroot/src/network/searchApi/data.api.ts +++ b/webroot/src/network/searchApi/data.api.ts @@ -23,6 +23,7 @@ export interface SearchParamsInterfaceLocal { licenseeFirstName?: string; licenseeLastName?: string; homeState?: string; + licenseScope?: string; dob?: string; privilegeState?: string; privilegePurchaseStartDate?: string; @@ -133,6 +134,7 @@ export class SearchDataApi implements DataApiInterface { licenseeLastName, dob, homeState, + licenseScope, privilegeState, privilegePurchaseStartDate, privilegePurchaseEndDate, @@ -153,6 +155,7 @@ export class SearchDataApi implements DataApiInterface { || licenseeLastName || dob || homeState + || licenseScope || privilegeState || privilegePurchaseStartDate || privilegePurchaseEndDate @@ -211,6 +214,18 @@ export class SearchDataApi implements DataApiInterface { }, }); } + if (licenseScope) { + conditions.push({ + nested: { + path: 'licenses', + query: { + term: { + 'licenses.licenseScope': licenseScope, + }, + }, + }, + }); + } // // Privilege search props // diff --git a/webroot/src/store/license/license.mutations.ts b/webroot/src/store/license/license.mutations.ts index 29e8892e2c..1e168e6169 100644 --- a/webroot/src/store/license/license.mutations.ts +++ b/webroot/src/store/license/license.mutations.ts @@ -76,15 +76,15 @@ export default { if (licenseeToUpdateIndex !== -1) { const currentLicenseeRecord = state.model[licenseeToUpdateIndex]; - const listFetchOnlyProps = ['licenseNumber', 'eligibility']; + const listFetchOnlyProps = ['licenseNumber', 'eligibility', 'licenseType']; // Some props are only returned on the list fetch, and we want to preserve those where possible. listFetchOnlyProps.forEach((listFetchOnlyProp) => { - const isCurrentRecordIncludingProp = Object.hasOwn(currentLicenseeRecord, listFetchOnlyProp); - const isNewRecordMissingProp = Object.hasOwn(licensee, listFetchOnlyProp); + const currentValue = currentLicenseeRecord[listFetchOnlyProp]; + const newValue = licensee[listFetchOnlyProp]; - if (isCurrentRecordIncludingProp && isNewRecordMissingProp) { - licensee[listFetchOnlyProp] = currentLicenseeRecord[listFetchOnlyProp]; + if (currentValue && !newValue) { + licensee[listFetchOnlyProp] = currentValue; } }); diff --git a/webroot/src/store/license/license.spec.ts b/webroot/src/store/license/license.spec.ts index 288f43efa6..5bbd9dc5d0 100644 --- a/webroot/src/store/license/license.spec.ts +++ b/webroot/src/store/license/license.spec.ts @@ -105,6 +105,30 @@ describe('License Store Mutations', () => { expect(state.model).to.matchPattern([licensee]); }); + it('should successfully update licensee (already in store - preserving list-only props)', () => { + const state = { + model: [{ + id: 1, licenseNumber: 'A-123', eligibility: 'eligible', licenseType: 'social worker' + }] + }; + const licensee = { + id: 1, licenseNumber: null, eligibility: null, licenseType: null + }; + + mutations[MutationTypes.STORE_UPDATE_LICENSEE](state, licensee); + + expect(state.model).to.matchPattern([{ + id: 1, licenseNumber: 'A-123', eligibility: 'eligible', licenseType: 'social worker' + }]); + }); + it('should successfully update licensee (already in store - not overwriting new list-only props)', () => { + const state = { model: [{ id: 1, licenseType: 'social worker' }] }; + const licensee = { id: 1, licenseType: 'clinical social worker' }; + + mutations[MutationTypes.STORE_UPDATE_LICENSEE](state, licensee); + + expect(state.model).to.matchPattern([{ id: 1, licenseType: 'clinical social worker' }]); + }); it('should successfully remove licensee (id missing)', () => { const state = {}; const licenseeId = ''; From 4c5f68962c56851ef962cd1e3bb2c0df02073fb4 Mon Sep 17 00:00:00 2001 From: John Sandoval Date: Fri, 4 Sep 2026 12:55:58 -0600 Subject: [PATCH 2/2] PR review feedback --- webroot/src/store/license/license.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webroot/src/store/license/license.spec.ts b/webroot/src/store/license/license.spec.ts index 5bbd9dc5d0..150e6c4aa4 100644 --- a/webroot/src/store/license/license.spec.ts +++ b/webroot/src/store/license/license.spec.ts @@ -105,7 +105,7 @@ describe('License Store Mutations', () => { expect(state.model).to.matchPattern([licensee]); }); - it('should successfully update licensee (already in store - preserving list-only props)', () => { + it('should successfully not update licensee (already in store - preserving list-only props)', () => { const state = { model: [{ id: 1, licenseNumber: 'A-123', eligibility: 'eligible', licenseType: 'social worker'