From f113d044ac303a819e2453e4cbd00b39870073af Mon Sep 17 00:00:00 2001 From: Sam Saravillo <7529759+samsaravillo@users.noreply.github.com> Date: Fri, 27 Jun 2025 16:04:51 -0700 Subject: [PATCH 01/10] bugfix/ab#29195 sonarQube fix and clean up code --- .../wwwroot/themes/ux2/table-utils.js | 22 +------------------ 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/applications/Unity.GrantManager/modules/Unity.Theme.UX2/src/Unity.Theme.UX2/wwwroot/themes/ux2/table-utils.js b/applications/Unity.GrantManager/modules/Unity.Theme.UX2/src/Unity.Theme.UX2/wwwroot/themes/ux2/table-utils.js index 990090fd4..a01f81f0b 100644 --- a/applications/Unity.GrantManager/modules/Unity.Theme.UX2/src/Unity.Theme.UX2/wwwroot/themes/ux2/table-utils.js +++ b/applications/Unity.GrantManager/modules/Unity.Theme.UX2/src/Unity.Theme.UX2/wwwroot/themes/ux2/table-utils.js @@ -209,7 +209,7 @@ function initializeDataTable(options) { try { dtApi = new $.fn.dataTable.Api(settings); - if (!dtApi || !dtApi.table().node()) { + if (!dtApi?.table()?.node()) { throw new Error('Invalid DataTable instance.'); } @@ -511,26 +511,6 @@ function toggleFilterRow() { $(this).popover('toggle'); $('#dtFilterRow').toggleClass('hidden'); } -function updateColvisButtonState($btn, api, colIndex) { - const visible = api.column(colIndex).visible(); - $btn.toggleClass('dt-button-active', visible); -} - -function syncColvisButtonStates(api) { - const aoColumns = api.settings()[0].aoColumns; - - let x = $('.dt-button-collection .dt-button'); - let z = $('.dt-button-collection a.dt-button'); - $('.dt-button-collection a.dt-button').each(function () { - const $btn = $(this); - const colName = $btn.attr('data-cv-name'); - - const colIndex = aoColumns.findIndex((col) => col.name === colName); - if (colIndex !== -1) { - updateColvisButtonState($btn, api, colIndex); - } - }); -} function findColumnByTitle(title, dataTable) { let columnIndex = dataTable From 22789ffc49751e3d984ac4aba1ec2b719a08c32b Mon Sep 17 00:00:00 2001 From: jpasta Date: Fri, 27 Jun 2025 16:28:32 -0700 Subject: [PATCH 02/10] bugfix/AB#29308-SuplierOrgMatch --- .../appsettings.Development.json | 32 +++++++++++++------ 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/appsettings.Development.json b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/appsettings.Development.json index 4ebac5540..c80bdc834 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/appsettings.Development.json +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/appsettings.Development.json @@ -2,6 +2,18 @@ "App": { "SelfUrl": "https://localhost:44342" }, + "AuthServer": { + "ClientSecret": "jFu4rn0dNhWLXK8aTtZFgKKpbgythXyQ" + }, + "S3": { + "AccessKeyId": "AKIA4BB43F4F79656631", + "Bucket": "econ-unity-dev", + "Endpoint": "https://econ.objectstore.gov.bc.ca", + "SecretAccessKey": "Hey3NgifaOl6LyckDwDOqF62NAH4uHIJ2v3G0PyO" + }, + "CssApi": { + "ClientSecret": "Rmt6GTnfoFH7gZ7BcPqgyFKHPkC8etI0" + }, "ConnectionStrings": { "Default": "Host=localhost;port=5432;Database=UnityGrantManager;Username=postgres;Password=admin", "Tenant": "Host=localhost;port=5432;Database=UnityGrantTenant;Username=postgres;Password=admin" @@ -28,19 +40,16 @@ "AllowUnregisteredVersions": true }, "Payments": { - "CasBaseUrl": "", - "CasClientId": "", - "CasClientSecret": "" + "CasBaseUrl": "https://cfs-systws.cas.gov.bc.ca:7025/ords/cas", + "CasClientId": "mjv_njxSHbvUmFLLB6DjUg..", + "CasClientSecret": "nVEQbamSmWVcHBWcPPJCyg.." }, "Notifications": { - "TeamsNotificationsWebhook": "", - "ChesUrl": "https://ches-dev.api.gov.bc.ca/api/v1", + "TeamsNotificationsWebhook": "https://bcgov.webhook.office.com/webhookb2/d7f6b10c-adf3-4dd1-ad14-8f526f197bd2@6fdb5200-3d0d-4a8a-b036-d3685e359adc/IncomingWebhook/2f6fa0633b614793b3073e087d043bc4/f366bba6-e526-4920-ad6f-ce6ae509430a", "ChesTokenUrl": "https://dev.loginproxy.gov.bc.ca/auth/realms/comsvcauth/protocol/openid-connect/token", - "ChesClientId": "", - "ChesClientSecret": "" - }, - "DataProtection": { - "IsEnabled": false + "ChesClientId": "CDACC9DF-581CC89F2F2", + "ChesClientSecret": "dLpB850zDdItNhcKzAdmm3f1U5gfXiNl", + "ChesBaseUri": "https://ches-dev.api.gov.bc.ca/api/v1" }, "Logging": { "LogLevel": { @@ -94,5 +103,8 @@ }, "IdentityProfileLogin": { "AutoCreateUser": true + }, + "DataProtection": { + "IsEnabled": false } } \ No newline at end of file From d12dd71559c70781382fb8cda5ec5c0b00577d6a Mon Sep 17 00:00:00 2001 From: jpasta Date: Fri, 27 Jun 2025 16:34:50 -0700 Subject: [PATCH 03/10] bugfix/AB#29308-SuplierOrgMatch --- .../Components/SupplierInfo/SupplierInfo.js | 16 +++++----- .../appsettings.Development.json | 32 ++++++------------- 2 files changed, 18 insertions(+), 30 deletions(-) diff --git a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Views/Shared/Components/SupplierInfo/SupplierInfo.js b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Views/Shared/Components/SupplierInfo/SupplierInfo.js index 7cab6c736..d3b602f9c 100644 --- a/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Views/Shared/Components/SupplierInfo/SupplierInfo.js +++ b/applications/Unity.GrantManager/modules/Unity.Payments/src/Unity.Payments.Web/Views/Shared/Components/SupplierInfo/SupplierInfo.js @@ -27,21 +27,21 @@ $(function () { function validateMatchingSupplierToOrgInfo() { const supplierName = (UIElements.supplierName.val() || '').toLowerCase().trim(); - + if (!supplierName) { UIElements.supplierOrgInfoErrorDiv.toggleClass('hidden', true); return; } - let isMatch = true; + const orgName = (UIElements.orgName.val() || '').toLowerCase().trim(); const nonRegisteredOrgName = (UIElements.nonRegisteredOrgName.val() || '').toLowerCase().trim(); - if(orgName != '') { - isMatch = !supplierName || !orgName || supplierName === orgName; - } else if(nonRegisteredOrgName != '') { - isMatch = !supplierName || !nonRegisteredOrgName || supplierName === nonRegisteredOrgName; - } - + // Match if either orgName or nonRegisteredOrgName matches supplierName + const isMatch = + (!orgName && !nonRegisteredOrgName) || + supplierName === orgName || + supplierName === nonRegisteredOrgName; + UIElements.supplierOrgInfoErrorDiv.toggleClass('hidden', isMatch); } diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/appsettings.Development.json b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/appsettings.Development.json index c80bdc834..4ebac5540 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/appsettings.Development.json +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/appsettings.Development.json @@ -2,18 +2,6 @@ "App": { "SelfUrl": "https://localhost:44342" }, - "AuthServer": { - "ClientSecret": "jFu4rn0dNhWLXK8aTtZFgKKpbgythXyQ" - }, - "S3": { - "AccessKeyId": "AKIA4BB43F4F79656631", - "Bucket": "econ-unity-dev", - "Endpoint": "https://econ.objectstore.gov.bc.ca", - "SecretAccessKey": "Hey3NgifaOl6LyckDwDOqF62NAH4uHIJ2v3G0PyO" - }, - "CssApi": { - "ClientSecret": "Rmt6GTnfoFH7gZ7BcPqgyFKHPkC8etI0" - }, "ConnectionStrings": { "Default": "Host=localhost;port=5432;Database=UnityGrantManager;Username=postgres;Password=admin", "Tenant": "Host=localhost;port=5432;Database=UnityGrantTenant;Username=postgres;Password=admin" @@ -40,16 +28,19 @@ "AllowUnregisteredVersions": true }, "Payments": { - "CasBaseUrl": "https://cfs-systws.cas.gov.bc.ca:7025/ords/cas", - "CasClientId": "mjv_njxSHbvUmFLLB6DjUg..", - "CasClientSecret": "nVEQbamSmWVcHBWcPPJCyg.." + "CasBaseUrl": "", + "CasClientId": "", + "CasClientSecret": "" }, "Notifications": { - "TeamsNotificationsWebhook": "https://bcgov.webhook.office.com/webhookb2/d7f6b10c-adf3-4dd1-ad14-8f526f197bd2@6fdb5200-3d0d-4a8a-b036-d3685e359adc/IncomingWebhook/2f6fa0633b614793b3073e087d043bc4/f366bba6-e526-4920-ad6f-ce6ae509430a", + "TeamsNotificationsWebhook": "", + "ChesUrl": "https://ches-dev.api.gov.bc.ca/api/v1", "ChesTokenUrl": "https://dev.loginproxy.gov.bc.ca/auth/realms/comsvcauth/protocol/openid-connect/token", - "ChesClientId": "CDACC9DF-581CC89F2F2", - "ChesClientSecret": "dLpB850zDdItNhcKzAdmm3f1U5gfXiNl", - "ChesBaseUri": "https://ches-dev.api.gov.bc.ca/api/v1" + "ChesClientId": "", + "ChesClientSecret": "" + }, + "DataProtection": { + "IsEnabled": false }, "Logging": { "LogLevel": { @@ -103,8 +94,5 @@ }, "IdentityProfileLogin": { "AutoCreateUser": true - }, - "DataProtection": { - "IsEnabled": false } } \ No newline at end of file From 366bb82e22f40d2a2a1e1ce343c204f51aea33ae Mon Sep 17 00:00:00 2001 From: Cyrus Parsons Date: Mon, 30 Jun 2025 10:59:32 -0700 Subject: [PATCH 04/10] feature/AB#29093-Added-Clear-Orgbook-Button --- .../Components/ApplicantInfo/Default.cshtml | 39 +- .../Components/ApplicantInfo/Default.js | 1207 +++++++++-------- 2 files changed, 637 insertions(+), 609 deletions(-) diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantInfo/Default.cshtml b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantInfo/Default.cshtml index 87cee84c9..8dd6b5f05 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantInfo/Default.cshtml +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantInfo/Default.cshtml @@ -61,18 +61,33 @@ - + + + + + + + + + + + @@ -174,7 +189,7 @@ - @* Zone Section : Contact Info *@ + @* Zone Section : Contact Info diff --git a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantInfo/Default.js b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantInfo/Default.js index d581ba82d..dd200c10b 100644 --- a/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantInfo/Default.js +++ b/applications/Unity.GrantManager/src/Unity.GrantManager.Web/Views/Shared/Components/ApplicantInfo/Default.js @@ -1,633 +1,646 @@ -abp.widgets.ApplicantInfo = function ($wrapper) { - let widgetManager = $wrapper.data('abp-widget-manager'); - - let widgetApi = { - getFilters: function () { - return { - applicationId: $wrapper.find('#ApplicantInfo_ApplicationId').val(), - applicationFormVersionId: $wrapper.find("#ApplicantInfo_ApplicationFormVersionId").val() - }; - }, - init: function (filters) { - let $widgetForm = $wrapper.find('form'); - - // Create a new form instance and store it on the widget API - this.zoneForm = new UnityZoneForm($widgetForm, { - saveButtonSelector: '#saveApplicantInfoBtn' - }); - - console.log("Applicant Info Initialized"); - - this.zoneForm.init(); - - // Set up additional event handlers here - this.setupEventHandlers(); - registerElectoralDistrictControls(this.zoneForm.form); - registerApplicantInfoSummaryDropdowns(this.zoneForm.form); +abp.widgets.ApplicantInfo = function ($wrapper) { + let widgetManager = $wrapper.data('abp-widget-manager'); + + let widgetApi = { + getFilters: function () { + return { + applicationId: $wrapper.find('#ApplicantInfo_ApplicationId').val(), + applicationFormVersionId: $wrapper.find("#ApplicantInfo_ApplicationFormVersionId").val() + }; + }, + init: function (filters) { + let $widgetForm = $wrapper.find('form'); + + // Create a new form instance and store it on the widget API + this.zoneForm = new UnityZoneForm($widgetForm, { + saveButtonSelector: '#saveApplicantInfoBtn' + }); + + console.log("Applicant Info Initialized"); + + this.zoneForm.init(); + + // Set up additional event handlers here + this.setupEventHandlers(); + registerElectoralDistrictControls(this.zoneForm.form); + registerApplicantInfoSummaryDropdowns(this.zoneForm.form); }, refresh: function () { widgetManager.refresh($wrapper); }, setupEventHandlers: function () { const self = this; - - PubSub.subscribe( - 'applicant_info_merged', - () => { - self.refresh(); - } + + PubSub.subscribe( + 'applicant_info_merged', + () => { + self.refresh(); + } ); - - // Save button handler + + // Save button handler self.zoneForm.saveButton.on('click', function () { let applicationId = document.getElementById('ApplicantInfo_ApplicationId').value; let applicantInfoSubmission = self.getPartialUpdate(); - try { - unity.grantManager.grantApplications.applicationApplicant - .updatePartialApplicantInfo(applicationId, applicantInfoSubmission) - .done(function () { - abp.notify.success('The Applicant Info has been updated.'); - self.zoneForm.resetTracking(); - PubSub.publish("refresh_detail_panel_summary"); - PubSub.publish('applicant_info_updated', applicantInfoSubmission); - }) - .fail(function (error) { - abp.notify.error('Failed to update Applicant Info.'); - console.log(error); - }); - } catch (error) { - abp.notify.error('An unexpected error occurred.'); - console.log(error); + try { + unity.grantManager.grantApplications.applicationApplicant + .updatePartialApplicantInfo(applicationId, applicantInfoSubmission) + .done(function () { + abp.notify.success('The Applicant Info has been updated.'); + self.zoneForm.resetTracking(); + PubSub.publish("refresh_detail_panel_summary"); + PubSub.publish('applicant_info_updated', applicantInfoSubmission); + }) + .fail(function (error) { + abp.notify.error('Failed to update Applicant Info.'); + console.log(error); + }); + } catch (error) { + abp.notify.error('An unexpected error occurred.'); + console.log(error); } }); }, getPartialUpdate: function () { let submissionPayload = this.serializeWidget(); - - const customIncludes = new Set(); - - if (typeof Flex === 'function' && Object.keys(submissionPayload.CustomFields || {}).length > 0) { - // Add Worksheet Metadata and filter conditions - submissionPayload.CorrelationId = $("#ApplicantInfo_ApplicationFormVersionId").val(); - submissionPayload.WorksheetId = $("#ApplicantInfo_WorksheetId").val(); - - // Normalize checkboxes to string for custom worksheets - $(`#Unity_GrantManager_ApplicationManagement_Applicant_Worksheet input:checkbox`).each(function () { - submissionPayload.CustomFields[this.name] = (this.checked).toString(); - }); - - customIncludes - .add('CustomFields') - .add('CorrelationId') - .add('WorksheetId'); - } - - customIncludes.add('ApplicantId'); - - let modifiedFieldData = Object.fromEntries( - Object.entries(submissionPayload).filter(([key, _]) => { - // Check if it's a modified widget field - return this.zoneForm.modifiedFields.has(key) || customIncludes.has(key) || key.startsWith('custom_'); - }) - ); - - let partialSubmissionPayload = { - modifiedFields: Array.from(this.zoneForm.modifiedFields), - data: unflattenObject(modifiedFieldData) - }; - + + const customIncludes = new Set(); + + if (typeof Flex === 'function' && Object.keys(submissionPayload.CustomFields || {}).length > 0) { + // Add Worksheet Metadata and filter conditions + submissionPayload.CorrelationId = $("#ApplicantInfo_ApplicationFormVersionId").val(); + submissionPayload.WorksheetId = $("#ApplicantInfo_WorksheetId").val(); + + // Normalize checkboxes to string for custom worksheets + $(`#Unity_GrantManager_ApplicationManagement_Applicant_Worksheet input:checkbox`).each(function () { + submissionPayload.CustomFields[this.name] = (this.checked).toString(); + }); + + customIncludes + .add('CustomFields') + .add('CorrelationId') + .add('WorksheetId'); + } + + customIncludes.add('ApplicantId'); + + let modifiedFieldData = Object.fromEntries( + Object.entries(submissionPayload).filter(([key, _]) => { + // Check if it's a modified widget field + return this.zoneForm.modifiedFields.has(key) || customIncludes.has(key) || key.startsWith('custom_'); + }) + ); + + let partialSubmissionPayload = { + modifiedFields: Array.from(this.zoneForm.modifiedFields), + data: unflattenObject(modifiedFieldData) + }; + return partialSubmissionPayload; }, - serializeWidget: function () { - let formData = this.zoneForm.serializeZoneArray(); - let submissionPayload = {}; - - // Process all form fields - $.each(formData, (_, input) => { - this.processFormField(submissionPayload, input); - }); - - return submissionPayload; + serializeWidget: function () { + let formData = this.zoneForm.serializeZoneArray(); + let submissionPayload = {}; + + // Process all form fields + $.each(formData, (_, input) => { + this.processFormField(submissionPayload, input); + }); + + return submissionPayload; }, processFormField: function (submissionPayload, input) { - const fieldName = input.name; + const fieldName = input.name; const inputElement = $(`[name="${fieldName}"]`); - // Handle checkboxes explicitly - if (inputElement.length && inputElement.attr('type') === 'checkbox') { - // Only process the actual checkbox, not the hidden field - // If multiple elements with the same name, pick the checkbox - const checkbox = inputElement.filter('[type="checkbox"]'); - if (checkbox.length) { - if (typeof Flex === 'function' && Flex?.isCustomField(input)) { - Flex.includeCustomFieldObj(submissionPayload, input); - } else { + // Handle checkboxes explicitly + if (inputElement.length && inputElement.attr('type') === 'checkbox') { + // Only process the actual checkbox, not the hidden field + // If multiple elements with the same name, pick the checkbox + const checkbox = inputElement.filter('[type="checkbox"]'); + if (checkbox.length) { + if (typeof Flex === 'function' && Flex?.isCustomField(input)) { + Flex.includeCustomFieldObj(submissionPayload, input); + } else { submissionPayload[fieldName] = checkbox.is(':checked'); - } - return; - } + } + return; + } + } + + // Existing logic for custom fields + if (typeof Flex === 'function' && Flex?.isCustomField(input)) { + Flex.includeCustomFieldObj(submissionPayload, input); + return; } - // Existing logic for custom fields - if (typeof Flex === 'function' && Flex?.isCustomField(input)) { - Flex.includeCustomFieldObj(submissionPayload, input); - return; - } - let fieldValue = input.value; - if (inputElement.hasClass('unity-currency-input') || inputElement.hasClass('numeric-mask')) { - fieldValue = fieldValue.replace(/,/g, ''); + if (inputElement.hasClass('unity-currency-input') || inputElement.hasClass('numeric-mask')) { + fieldValue = fieldValue.replace(/,/g, ''); } - - if (fieldName.startsWith('ApplicantInfo.')) { - const propertyName = fieldName.split('.')[1]; - submissionPayload[propertyName] = fieldValue; - } else { - submissionPayload[fieldName] = fieldValue; + + if (fieldName.startsWith('ApplicantInfo.')) { + const propertyName = fieldName.split('.')[1]; + submissionPayload[propertyName] = fieldValue; + } else { + submissionPayload[fieldName] = fieldValue; } } } - + return widgetApi; -} - -$(function () { - // Initialize widget through ABP's widget system instead of global object - abp.zones = abp.zones || {}; - abp.zones.applicantInfo = $('[data-widget-name="ApplicantInfo"]') - .data('abp-widget-api') || null; - - $('#applicantLookupSelect').select2({ - ajax: { - url: '/api/app/applicant/applicant-look-up-autocomplete-query', - dataType: 'json', - delay: 250, - data: function (params) { - return { applicantLookUpQuery: params.term }; - }, - processResults: function (data) { - return { - results: data.map(function (item) { - const res = { - id: item.Id, - text: `${item.UnityApplicantId?.trim() ? item.UnityApplicantId : 'None'} / ${item.ApplicantName}`, - ApplicantName: item.ApplicantName, - OrgName: item.OrgName, - OrgNumber: item.OrgNumber, - NonRegOrgName: item.NonRegOrgName, - OrganizationType: item.OrganizationType, - OrganizationSize: item.OrganizationSize, - OrgStatus: item.OrgStatus, - IndigenousOrgInd: item.IndigenousOrgInd, - Sector: item.Sector, - SubSector: item.SubSector, - SectorSubSectorIndustryDesc: item.SectorSubSectorIndustryDesc, - FiscalDay: item.FiscalDay, - FiscalMonth: item.FiscalMonth, - UnityApplicantId: item.UnityApplicantId - }; - return res - }) - }; - } - }, - minimumInputLength: 3, - placeholder: 'Start typing applicant name or number to search for applicant...' - }); - - $('#applicantLookupSelect').on('select2:select', function (e) { - $('#mergeApplicantsMergeBtn').prop('disabled', false); - let selectedData = e.params.data; - - // Gather existing values from the form - let getVal = id => $(`#${id}`).val() || ''; - let existing = { - ApplicantId: getVal('ApplicantId'), - UnityApplicantId: getVal('ApplicantSummary_UnityApplicantId'), - ApplicantName: $('.application-details-breadcrumb .applicant-name').text(), - OrgName: getVal('ApplicantSummary_OrgName'), - OrgNumber: getVal('ApplicantSummary_OrgNumber'), - NonRegOrgName: getVal('ApplicantSummary_NonRegOrgName'), - OrganizationType: getVal('ApplicantSummary_OrganizationType'), - OrganizationSize: getVal('ApplicantSummary_OrganizationSize'), - OrgStatus: getVal('ApplicantSummary_OrgStatus'), - IndigenousOrgInd: $('#indigenousOrgInd').is(':checked') ? 'Yes' : 'No', - Sector: getVal('ApplicantSummary_Sector'), - SubSector: getVal('ApplicantSummary_SubSector'), - SectorSubSectorIndustryDesc: getVal('ApplicantSummary_SectorSubSectorIndustryDesc'), - FiscalDay: getVal('ApplicantSummary_FiscalDay'), - FiscalMonth: getVal('ApplicantSummary_FiscalMonth') - }; - - let newData = { - ApplicantId: selectedData.id || '', - UnityApplicantId: selectedData.UnityApplicantId || '', - ApplicantName: selectedData.ApplicantName || '', - OrgName: selectedData.OrgName || '', - OrgNumber: selectedData.OrgNumber || '', - NonRegOrgName: selectedData.NonRegOrgName || '', - OrganizationType: selectedData.OrganizationType || '', - OrganizationSize: selectedData.OrganizationSize || '', - OrgStatus: selectedData.OrgStatus || '', - IndigenousOrgInd: selectedData.IndigenousOrgInd || '', - Sector: selectedData.Sector || '', - SubSector: selectedData.SubSector || '', - SectorSubSectorIndustryDesc: selectedData.SectorSubSectorIndustryDesc || '', - FiscalDay: selectedData.FiscalDay || '', - FiscalMonth: selectedData.FiscalMonth || '' - }; - - $('#existing_ApplicantNameHeader').text(existing.ApplicantName); - $('#new_ApplicantNameHeader').text(newData.ApplicantName); - - // Fill modal fields - for (const key in existing) { - $(`#existing_${key}`).text(existing[key]); - $(`#new_${key}`).text(newData[key]); - $(`input[name="merge_${key}"][value="existing"]`).prop('checked', true); - } - - // Show step 1, hide step 2 - $('#mergeApplicantsStep1').show(); - $('#mergeApplicantsStep2').hide(); - - // Remove previous handlers - $('#mergeApplicantsNextBtn').off('click'); - $('#mergeApplicantsBackBtn').off('click'); - $('#mergeApplicantsMergeBtn').off('click'); - $('#mergeDuplicateApplicantsModal').off('hidden.bs.modal'); - - // Next button: go to confirmation - $('#mergeApplicantsNextBtn').on('click', function () { - $('#mergeApplicantsStep1').hide(); - $('#mergeApplicantsStep2').show(); - }); - - // Back button: return to comparison - $('#mergeApplicantsBackBtn').on('click', function () { - $('#mergeApplicantsStep2').hide(); - $('#mergeApplicantsStep1').show(); - }); - - // Merge button: apply selected values to form - $('#mergeApplicantsMergeBtn').on('click', async function () { - $('#mergeApplicantsMergeBtn').prop('disabled', true); - $('#mergeApplicantsSpinner').show(); - - let selectedPrincipal = $('input[name="merge_ApplicantId"]:checked').val(); - let principalApplicantId = selectedPrincipal === 'existing' ? existing.ApplicantId : newData.ApplicantId; - let nonPrincipalApplicantId = selectedPrincipal === 'existing' ? newData.ApplicantId : existing.ApplicantId; - let applicationId = $('#ApplicantInfoViewApplicationId').val(); - - // Merge and update applicant info - let mergedApplicantInfo = {}; - if (principalApplicantId) { - mergedApplicantInfo = getMergedApplicantInfo(existing, newData); - mergedApplicantInfo.ApplicantId = principalApplicantId; - - let formData = $("#ApplicantInfoForm").serializeArray(); - let ApplicantInfoObj = {}; - let formVersionId = $("#ApplicationFormVersionId").val(); - let worksheetId = $("#WorksheetId").val(); - - $.each(formData, function (_, input) { - if (typeof Flex === 'function' && Flex?.isCustomField(input)) { - Flex.includeCustomFieldObj(ApplicantInfoObj, input); - } - else { - ApplicantInfoObj[input.name] = input.value; - - if (ApplicantInfoObj[input.name] == '') { - ApplicantInfoObj[input.name] = null; - } - } - }); - - $(`#ApplicantInfoForm input:checkbox`).each(function () { - ApplicantInfoObj[this.name] = (this.checked).toString(); - }); - if (typeof Flex === 'function') { - Flex?.setCustomFields(ApplicantInfoObj); - } - - Object.assign(ApplicantInfoObj, mergedApplicantInfo); - Object.keys(ApplicantInfoObj).forEach(key => { - if (ApplicantInfoObj[key] === "") { - ApplicantInfoObj[key] = null; - } - }); - - const orgName = $('#ApplicantSummary_OrgName').val(); - ApplicantInfoObj['ApplicantSummary.OrgName'] = orgName; - const orgNumber = $('#ApplicantSummary_OrgNumber').val(); - ApplicantInfoObj['ApplicantSummary.OrgNumber'] = orgNumber; - const orgStatus = $('#ApplicantSummary_OrgStatus').val(); - ApplicantInfoObj['ApplicantSummary.OrgStatus'] = orgStatus; - const organizationType = $('#ApplicantSummary_OrganizationType').val(); - ApplicantInfoObj['OrganizationType'] = organizationType; - - const indigenousOrgInd = $('#indigenousOrgInd').is(":checked"); - ApplicantInfoObj['IndigenousOrgInd'] = indigenousOrgInd ? "Yes" : "No"; - ApplicantInfoObj['correlationId'] = formVersionId; - ApplicantInfoObj['worksheetId'] = worksheetId; - ApplicantInfoObj.ApplicantId = principalApplicantId; - - try { - await handleApplicantMerge(applicationId, principalApplicantId, nonPrincipalApplicantId, newData, ApplicantInfoObj); - } catch (err) { - console.error(err); - } - } - - // Triggers a refresh of the ApplicantInfo widget on merge - PubSub.publish('applicant_info_merged'); - - $('#mergeApplicantsSpinner').hide(); - $('#mergeDuplicateApplicantsModal').modal('hide'); - }); - - // On modal close, clear the ApplicantLookUp field - $('#mergeDuplicateApplicantsModal').on('hidden.bs.modal', function () { - $('#applicantLookupSelect').val(null).trigger('change'); - }); - - // Show the modal - $('#mergeDuplicateApplicantsModal').modal('show'); - - }); - - - $('#selectAllExistingBtn').on('click', function () { - $('#mergeApplicantsStep1 input[type="radio"][value="existing"]').each(function () { - $(this).prop('checked', true); - }); - }); - - $('#selectAllNewBtn').on('click', function () { - $('#mergeApplicantsStep1 input[type="radio"][value="new"]').each(function () { - $(this).prop('checked', true); - }); - }); -}); - - -// Move to zone-extensions -function unflattenObject(flatObj) { - const result = {}; - for (const flatKey in flatObj) { - const value = flatObj[flatKey]; - if (!flatKey) continue; - const keys = flatKey.split('.'); - let cur = result; - for (let i = 0; i < keys.length; i++) { - const k = keys[i]; - if (i === keys.length - 1) { - cur[k] = value; - } else { - cur[k] = cur[k] || {}; - cur = cur[k]; - } - } - } - return result; -} - -function registerElectoralDistrictControls($container) { - $container.find('[data-bs-toggle="tooltip"]').tooltip(); - setElectoralDistrictLockState(true); - - const $electoralType = $('#ApplicantElectoralAddressType'); - - // Delegate change event for both address groups - $container.on('change', '.physical-address-fields-group input, .mailing-address-fields-group input', function () { - const type = $electoralType.val(); - if ( - ((type === "PhysicalAddress" && $(this).closest('.physical-address-fields-group').length) || - (type === "MailingAddress" && $(this).closest('.mailing-address-fields-group').length)) && - !electoralDistrictLocked - ) { - refreshApplicantElectoralDistrict(); - } - }); -} - -function registerApplicantInfoSummaryDropdowns($container) { - $container.find('#ApplicantSummary_Sector').on('change', function () { - const selectedValue = $(this).val(); - let sectorList = JSON.parse($('#orgApplicationSectorList').text()); - - let childDropdown = $('#ApplicantSummary_SubSector'); - childDropdown.empty(); - - let subSectors = sectorList.find(sector => (sector.sectorName === selectedValue))?.subSectors; - childDropdown.append($(' - @* Zone Section : Contact Info + @* Zone Section : Contact Info *@ From d01924730d80ad5c6643be901c208ef56149d61d Mon Sep 17 00:00:00 2001 From: Stephan McColm Date: Wed, 2 Jul 2025 17:34:02 -0700 Subject: [PATCH 10/10] =?UTF-8?q?feature/AB#29422=20=E2=80=A2=20Updated=20?= =?UTF-8?q?comprehensive=20checks=20for=20CHEFS=20data=20mapping=20across?= =?UTF-8?q?=20multiple=20panels=20(UI=20summary,=20application=20detail,?= =?UTF-8?q?=20review=20&=20assessment,=20and=20project=20info).=20?= =?UTF-8?q?=E2=80=A2=20Updated=20tests=20for=20the=20Applicant=20Info=20ta?= =?UTF-8?q?b,=20including=20value=20assertions=20and=20textarea=20validati?= =?UTF-8?q?on.=20=E2=80=A2=20Updated=20tests=20for=20the=20Sector=20and=20?= =?UTF-8?q?Sub-sector=20dropdowns=20to=20verify=20expected=20options.=20?= =?UTF-8?q?=E2=80=A2=20Verified=20Payment=20Info=20and=20Submission=20tab?= =?UTF-8?q?=20data,=20along=20with=20logout=20functionality.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Unity.AutoUI/cypress/e2e/chefsdata.cy.ts | 354 +++++++++--------- 1 file changed, 183 insertions(+), 171 deletions(-) diff --git a/applications/Unity.AutoUI/cypress/e2e/chefsdata.cy.ts b/applications/Unity.AutoUI/cypress/e2e/chefsdata.cy.ts index 48432f83d..5f8bf0f6a 100644 --- a/applications/Unity.AutoUI/cypress/e2e/chefsdata.cy.ts +++ b/applications/Unity.AutoUI/cypress/e2e/chefsdata.cy.ts @@ -1,175 +1,187 @@ /// describe('Unity Login and check data from CHEFS', () => { - - it('Verify Login', () => { - cy.login() - }) - // 19.) Verify that the info panel populates with mapped data - it('Verify the UI is populated with valid data from CHEFS', () => { - - cy.getSubmissionDetail('confirmationID').then(id => {cy.log(`Confirmation ID: ${id}`);}); - - cy.get('#search').should('exist').clear(); // Ensure the field exists and clear its contents - cy.get('#search').click() // click the search field - cy.getSubmissionDetail('confirmationID').then(id => cy.get('#search').type(id)); // Fetch the confirmation ID and type it into the search field - cy.getSubmissionDetail('confirmationID').then(id => cy.contains('tr', id).find('.checkbox-select').click()); // Fetch the confirmation ID, find its row, and click the checkbox - - cy.get('#applicationLink').should('exist').click() // open the info panel + + it('Verify Login', () => { + cy.login() + }) // 19.) Verify that the info panel populates with mapped data - // Category: AutoUI - cy.get('label[for="Category"]').next('.display-input').should('include.text', 'AutoUI'); - // Organization Name: DOLPHIN ASPHALT - cy.get('label[for="OrganizationName"]').next('.display-input').should('include.text', 'DOLPHIN ASPHALT') - // Organization #: - cy.get('label[for="OrganizationNumber"]').next('.display-input').should('include.text', 'FM0162628') - // Economic Region: Kootenay - cy.get('label[for="EconomicRegion"]').next('.display-input').should('include.text', 'Kootenay') - // Regional District: East Kootenay - cy.get('label[for="RegionalDistrict"]').next('.display-input').should('include.text', 'East Kootenay') - // Community: East Kootenay B - cy.get('label[for="Community"]').next('.display-input').should('include.text', 'East Kootenay B') - // Requested Amount: $89,000.00 - cy.get('label[for="RequestedAmount"]').next('.display-input').should('include.text', '$89,000.00') - // Total Project Budget: $125,000.00 - cy.get('label[for="ProjectBudget"]').next('.display-input').should('include.text', '$125,000.00') - // Sector: Other services (except public administration) - cy.get('label[for="Sector"]').next('.display-input').should('include.text', 'Other services (except public administration)') - cy.get('#closeSummaryCanvas').click() - // 20.) Verify that the details panel populates with mapped data - cy.get('#externalLink').should('exist').click() //open the application - // Category: AutoUI - cy.get('label[for="Category"]').next('.display-input').should('include.text', 'AutoUI') - // Organization Name: DOLPHIN ASPHALT - cy.get('label[for="OrganizationName"]').next('.display-input').should('include.text', 'DOLPHIN ASPHALT') - // Organization #: - cy.get('label[for="OrganizationNumber"]').next('.display-input').should('include.text', 'FM0162628') - // Economic Region: Kootenay - cy.get('label[for="EconomicRegion"]').next('.display-input').should('include.text', 'Kootenay') - // Regional District: East Kootenay - cy.get('label[for="RegionalDistrict"]').next('.display-input').should('include.text', 'East Kootenay') - // Community: East Kootenay B - cy.get('label[for="Community"]').next('.display-input').should('include.text', 'East Kootenay B') - // Requested Amount: $89,000.00 - cy.get('label[for="RequestedAmount"]').next('.display-input').should('include.text', '$89,000.00') - // Total Project Budget: $125,000.00 - cy.get('label[for="ProjectBudget"]').next('.display-input').should('include.text', '$125,000.00') - // Sector: Other services (except public administration) - cy.get('label[for="Sector"]').next('.display-input').should('include.text', 'Other services (except public administration)') - // 21.) Verify that the Review & Assessment tab populates with mapped data - cy.get('#nav-review-and-assessment-tab').should('exist').click() // open the Review & Assessment tab - // Requested Amount: $89,000.00 - cy.get('#RequestedAmountInputAR').should('have.value', '89,000.00') - // Total Project Budget: $125,000.00 - cy.get('#TotalBudgetInputAR').should('have.value', '125,000.00') - // 22.) Verify that the Project Info tab populates with mapped data - cy.get('#nav-project-info-tab').should('exist').click() // open the Project Info tab - // Project Name - cy.get('#ProjectInfo_ProjectName').should('have.value', 'Hanbury Development Initiative - Phase 2') - // Project Start Date: 2026-01-05 - cy.get('#startDate').should('have.value', '2026-01-05') - // Project End Date: 2027-03-11 - cy.get('#ProjectInfo_ProjectEndDate').should('have.value', '2027-03-11') - // Requested Amount: $89,000.00 - cy.get('#RequestedAmountInputPI').should('have.value', '89,000.00') - // Total Project Budget: $125,000.00 - cy.get('#TotalBudgetInputPI').should('have.value', '125,000.00') - // Acquisition: No - cy.get('#ProjectInfo_Acquisition').should('have.value', 'NO') - // Forestry/Non-Forestry: Forestry - cy.get('#ProjectInfo_Forestry').should('have.value', 'FORESTRY') - // Forestry Focus: Secondary/Value-Added/Not Mass Timber (value="SECONDARY") - cy.get('#ProjectInfo_ForestryFocus').should('have.value', 'SECONDARY') - // Economic Region: Kootenay - cy.get('#economicRegions').should('have.value', 'Kootenay') - // Regional District: East Kootenay - cy.get('#regionalDistricts').should('have.value', 'East Kootenay') - // Community: East Kootenay B - cy.get('#communities').should('have.value', 'East Kootenay B') - // Community Population: 38 - cy.get('#ProjectInfo_CommunityPopulation').should('have.value', '38') - // Electoral District: Kootenay-Rockies - cy.get('#ProjectInfo_ElectoralDistrict').should('have.value', 'Kootenay-Rockies') - // Place: Hanbury - cy.get('#ProjectInfo_Place').should('have.value', 'Hanbury') - // 23.) Verify that the Applicant Info tab populates with mapped data - cy.get('#nav-organization-info-tab').should('exist').click() // open the Applicant Info tab - // Organization Name: DOLPHIN ASPHALT - cy.get('#ApplicantInfo_OrgName').should('have.value', 'DOLPHIN ASPHALT') - // Organization #: FM0162628 - cy.get('#ApplicantInfo_OrgNumber').should('have.value', 'FM0162628') - // Other Sector/Sub/Industry Description: Stone Aggregate Recycling - cy.get('#ApplicantInfo_SectorSubSectorIndustryDesc').should('have.value', 'Stone Aggregate Recycling') - // Full Name: Jeff Gordon - cy.get('#ApplicantInfo_ContactFullName').should('have.value', 'Jeff Gordon') - // Title: Sr. Analyst - cy.get('#ApplicantInfo_ContactTitle').should('have.value', 'Sr. Analyst') - // Email: Jeff.Gordon@Dolphin.ca - cy.get('#ApplicantInfo_ContactEmail').should('have.value', 'Jeff.Gordon@Dolphin.ca') - // Business Phone: (250) 621-3217 - cy.get('#ApplicantInfo_ContactBusinessPhone').should('have.value', '(250) 621-3217') - // Cell Phone: (887) 362-1459 - cy.get('#ApplicantInfo_ContactCellPhone').should('have.value', '(887) 362-1459') - // (Physical Address) - // Street: 24th Avenue South - cy.get('#ApplicantInfo_PhysicalAddressStreet').should('have.value', '24th Avenue South') - // Street 2: Room 409 - cy.get('#ApplicantInfo_PhysicalAddressStreet2').should('have.value', 'Room 409') - // Unit: 19 - cy.get('#ApplicantInfo_PhysicalAddressUnit').should('have.value', '19') - // City: Cranbrook - cy.get('#ApplicantInfo_PhysicalAddressCity').should('have.value', 'Cranbrook') - // Province: British Columbia - cy.get('#ApplicantInfo_PhysicalAddressProvince').should('have.value', 'British Columbia') - // Postal Code: V1C 3H8 - cy.get('#ApplicantInfo_PhysicalAddressPostalCode').should('have.value', 'V1C 3H8') - // (Mailing Address) - // Street: 2567 Shaughnessy Street - cy.get('#ApplicantInfo_MailingAddressStreet').should('have.value', '2567 Shaughnessy Street') - // Street 2: PO Box 905 - cy.get('#ApplicantInfo_MailingAddressStreet2').should('have.value', 'PO Box 905') - // Unit: 22 - cy.get('#ApplicantInfo_MailingAddressUnit').should('have.value', '22') - // City: Hanbury - cy.get('#ApplicantInfo_MailingAddressCity').should('have.value', 'Hanbury') - // Province: British Columbia - cy.get('#ApplicantInfo_MailingAddressProvince').should('have.value', 'British Columbia') - // Postal Code: V1C 4T6 - cy.get('#ApplicantInfo_MailingAddressPostalCode').should('have.value', 'V1C 4T6') - // (Signing Authority) - // Full Name: Maximillion Cooper - cy.get('#ApplicantInfo_SigningAuthorityFullName').should('have.value', 'Maximillion Cooper') - // Title: Consultant - cy.get('#ApplicantInfo_SigningAuthorityTitle').should('have.value', 'Consultant') - // Email: Maximillion.Cooper@Dolphin.ca - cy.get('#ApplicantInfo_SigningAuthorityEmail').should('have.value', 'Maximillion.Cooper@Dolphin.ca') - // Business Phone: (250) 841-2511 - cy.get('#ApplicantInfo_SigningAuthorityBusinessPhone').should('have.value', '(250) 841-2511') - // Phone: (657) 456-5413 - cy.get('#ApplicantInfo_SigningAuthorityCellPhone').should('have.value', '(657) 456-5413') - // 24.) Verify that the Sector and Subsector Select Lists have a valid list of values. - // Check if the sector dropdown contains an option for "Manufacturing" - cy.get('#orgSectorDropdown').should('contain', 'Manufacturing') - // Select manufacturing - cy.get('#orgSectorDropdown').select('Manufacturing') - // Array of all expected options to check for in the Subsector list of values. - const options = ['Apparel manufacturing', 'Beverage and tobacco product manufacturing', 'Chemical manufacturing', 'Computer and electronic product manufacturing', 'Electrical equipment, appliance, and component manufacturing', 'Fabricated metal product manufacturing', 'Food manufacturing', 'Furniture and related product manufacturing', 'Leather and allied product manufacturing', 'Machinery manufacturing', 'Miscellaneous manufacturing', 'Non-metallic mineral product manufacturing', 'Other', 'Paper manufacturing', 'Petroleum and coal product manufacturing', 'Plastics and rubber products manufacturing', 'Primary metal manufacturing', 'Printing and related support activities', 'Textile mills', 'Textile product mills', 'Transportation equipment manufacturing', 'Wood product manufacturing'] - // Check if the dropdown contains each expected option in the options array - options.forEach(option => {cy.get('#orgSubSectorDropdown').select(option).should('have.value', option) - }) - // 25 Verify that the Payment Info tab populates with mapped data - cy.get('#nav-payment-info-tab').should('exist').click() // open the Payment Info tab - // Requested Amount: 89,000.00 - cy.get('#RequestedAmount').should('have.value', '89,000.00') - // 26.) Verify that the Submission tab populates with all form data - cy.get('#nav-summery-tab').should('exist').click() // open the Submission tab - const headers = ['1. INTRODUCTION', '2. ELIGIBILITY', '3. APPLICANT INFORMATION','4. PROJECT INFORMATION', '5. PROJECT TIMELINES', '6. PROJECT BUDGET', '7. ATTESTATION']; - headers.forEach(header => { - cy.contains('h4', header) - .should('exist') - .click(); - }); - }) - it('Verify Logout', () => { - cy.logout() - }) + it('Verify the UI is populated with valid data from CHEFS', () => { + + cy.getSubmissionDetail('confirmationID').then(id => { cy.log(`Confirmation ID: ${id}`); }); + + cy.get('#search').should('exist').clear(); // Ensure the field exists and clear its contents + cy.get('#search').click() // click the search field + cy.getSubmissionDetail('confirmationID').then(id => cy.get('#search').type(id)); // Fetch the confirmation ID and type it into the search field + cy.getSubmissionDetail('confirmationID').then(id => cy.contains('tr', id).find('.checkbox-select').click()); // Fetch the confirmation ID, find its row, and click the checkbox + + cy.get('#applicationLink').should('exist').click() // open the info panel + // 19.) Verify that the info panel populates with mapped data + // Category: AutoUI + cy.get('label[for="Category"]').next('.display-input').should('include.text', 'AutoUI'); + // Organization Name: DOLPHIN ASPHALT + cy.get('label.display-input-label[for="OrganizationName"]').next('div.display-input').should('contain.text', 'DOLPHIN ASPHALT') + // Organization #: + cy.get('label.display-input-label[for="OrganizationNumber"]').next('div.display-input').should('contain.text', 'FM0162628') + // Economic Region: Kootenay + cy.get('label[for="EconomicRegion"]').next('.display-input').should('include.text', 'Kootenay') + // Regional District: East Kootenay + cy.get('label[for="RegionalDistrict"]').next('.display-input').should('include.text', 'East Kootenay') + // Community: East Kootenay B + cy.get('label[for="Community"]').next('.display-input').should('include.text', 'East Kootenay B') + // Requested Amount: $89,000.00 + cy.get('label[for="RequestedAmount"]').next('.display-input').should('include.text', '$89,000.00') + // Total Project Budget: $125,000.00 + cy.get('label[for="ProjectBudget"]').next('.display-input').should('include.text', '$125,000.00') + // Sector: Other services (except public administration) + cy.get('label[for="Sector"]').next('.display-input').should('include.text', 'Other services (except public administration)') + cy.get('#closeSummaryCanvas').click() + // 20.) Verify that the details panel populates with mapped data + cy.get('#externalLink').should('exist').click() //open the application + // Category: AutoUI + cy.get('label[for="Category"]').next('.display-input').should('include.text', 'AutoUI') + // Organization Name: DOLPHIN ASPHALT + cy.get('label[for="OrganizationName"]').next('.display-input').should('include.text', 'DOLPHIN ASPHALT') + // Organization #: + cy.get('label[for="OrganizationNumber"]').next('.display-input').should('include.text', 'FM0162628') + // Economic Region: Kootenay + cy.get('label[for="EconomicRegion"]').next('.display-input').should('include.text', 'Kootenay') + // Regional District: East Kootenay + cy.get('label[for="RegionalDistrict"]').next('.display-input').should('include.text', 'East Kootenay') + // Community: East Kootenay B + cy.get('label[for="Community"]').next('.display-input').should('include.text', 'East Kootenay B') + // Requested Amount: $89,000.00 + cy.get('label[for="RequestedAmount"]').next('.display-input').should('include.text', '$89,000.00') + // Total Project Budget: $125,000.00 + cy.get('label[for="ProjectBudget"]').next('.display-input').should('include.text', '$125,000.00') + // Sector: Other services (except public administration) + cy.get('label[for="Sector"]').next('.display-input').should('include.text', 'Other services (except public administration)') + // 21.) Verify that the Review & Assessment tab populates with mapped data + cy.get('#nav-review-and-assessment-tab').should('exist').click() // open the Review & Assessment tab + // Requested Amount: $89,000.00 + cy.get('#RequestedAmountInputAR').should('have.value', '89,000.00') + // Total Project Budget: $125,000.00 + cy.get('#TotalBudgetInputAR').should('have.value', '125,000.00') + // 22.) Verify that the Project Info tab populates with mapped data + cy.get('#nav-project-info-tab').should('exist').click() // open the Project Info tab + // Project Name + cy.get('#ProjectInfo_ProjectName').should('have.value', 'Hanbury Development Initiative - Phase 2') + // Project Start Date: 2026-01-05 + cy.get('#startDate').should('have.value', '2026-01-05') + // Project End Date: 2027-03-11 + cy.get('#ProjectInfo_ProjectEndDate').should('have.value', '2027-03-11') + // Requested Amount: $89,000.00 + cy.get('#RequestedAmountInputPI').should('have.value', '89,000.00') + // Total Project Budget: $125,000.00 + cy.get('#TotalBudgetInputPI').should('have.value', '125,000.00') + // Acquisition: No + cy.get('#ProjectInfo_Acquisition').should('have.value', 'NO') + // Forestry/Non-Forestry: Forestry + cy.get('#ProjectInfo_Forestry').should('have.value', 'FORESTRY') + // Forestry Focus: Secondary/Value-Added/Not Mass Timber (value="SECONDARY") + cy.get('#ProjectInfo_ForestryFocus').should('have.value', 'SECONDARY') + // Economic Region: Kootenay + cy.get('#economicRegions').should('have.value', 'Kootenay') + // Regional District: East Kootenay + cy.get('#regionalDistricts').should('have.value', 'East Kootenay') + // Community: East Kootenay B + cy.get('#communities').should('have.value', 'East Kootenay B') + // Community Population: 38 + cy.get('#ProjectInfo_CommunityPopulation').should('have.value', '38') + // Electoral District: Kootenay-Rockies + cy.get('#ProjectInfo_ElectoralDistrict').should('have.value', 'Kootenay-Rockies') + // Place: Hanbury + cy.get('#ProjectInfo_Place').should('have.value', 'Hanbury') + + // 23.) open the Applicant Info tab + it('23. Applicant Info tab shows the mapped data', () => { + // 1. open the pane + cy.contains('a.nav-link', 'Applicant Info').click() + + // 2. wait for the Applicant Info fieldset, then work inside it + cy.get('fieldset[name$="Applicant_Summary"]', { timeout: 10_000 }) + .should('be.visible') + .as('app') // alias for scoping + + // 3. simple value assertions + const plainInputs: [string, string][] = [ + ['#ApplicantSummary_OrgName', 'DOLPHIN ASPHALT'], + ['#ApplicantSummary_OrgNumber', 'FM0162628'], + ['#ApplicantSummary_ContactFullName', 'Jeff Gordon'], + ['#ApplicantSummary_ContactTitle', 'Sr. Analyst'], + ['#ApplicantSummary_ContactEmail', 'Jeff.Gordon@Dolphin.ca'], + ['#ApplicantSummary_ContactBusinessPhone', '(250) 621-3217'], + ['#ApplicantSummary_ContactCellPhone', '(887) 362-1459'], + ['#ApplicantSummary_PhysicalAddressStreet', '24th Avenue South'], + ['#ApplicantSummary_PhysicalAddressStreet2', 'Room 409'], + ['#ApplicantSummary_PhysicalAddressUnit', '19'], + ['#ApplicantSummary_PhysicalAddressCity', 'Cranbrook'], + ['#ApplicantSummary_PhysicalAddressProvince', 'British Columbia'], + ['#ApplicantSummary_PhysicalAddressPostalCode', 'V1C 3H8'], + ['#ApplicantInfo_MailingAddressStreet', '2567 Shaughnessy Street'], + ['#ApplicantInfo_MailingAddressStreet2', 'PO Box 905'], + ['#ApplicantInfo_MailingAddressUnit', '22'], + ['#ApplicantInfo_MailingAddressCity', 'Hanbury'], + ['#ApplicantInfo_MailingAddressProvince', 'British Columbia'], + ['#ApplicantInfo_MailingAddressPostalCode', 'V1C 4T6'], + ['#ApplicantInfo_SigningAuthorityFullName', 'Maximillion Cooper'], + ['#ApplicantInfo_SigningAuthorityTitle', 'Consultant'], + ['#ApplicantInfo_SigningAuthorityEmail', 'Maximillion.Cooper@Dolphin.ca'], + ['#ApplicantInfo_SigningAuthorityBusinessPhone', '(250) 841-2511'], + ['#ApplicantInfo_SigningAuthorityCellPhone', '(657) 456-5413'] + ] + + plainInputs.forEach(([selector, expected]) => { + cy.get('@app').find(selector).should('have.value', expected) + }) + + // 4. textarea requires .invoke('val') + cy.get('@app') + .find('#ApplicantSummary_SectorSubSectorIndustryDesc') + .invoke('val') + .should('equal', 'Stone Aggregate Recycling') + }) + + // 24.) Sector and Sub-sector lists + it('24. Sector and Sub-sector dropdowns behave', () => { + // open Applicant Info + cy.contains('a.nav-link', 'Applicant Info').click() + + // locate the Sector and Sub-sector