From a4d2384a33f39c7097042ae4da8cb2165ada8b12 Mon Sep 17 00:00:00 2001 From: R Ranathunga Date: Fri, 22 Nov 2024 13:10:57 -0800 Subject: [PATCH 01/21] fix: browser compatibility on toSorted --- app/components/AnalystDashboard/AllDashboard.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/components/AnalystDashboard/AllDashboard.tsx b/app/components/AnalystDashboard/AllDashboard.tsx index d9e448a531..88c3787171 100644 --- a/app/components/AnalystDashboard/AllDashboard.tsx +++ b/app/components/AnalystDashboard/AllDashboard.tsx @@ -536,7 +536,7 @@ const AllDashboardTable: React.FC = ({ query }) => { allApplications.edges.map((edge) => edge.node?.intakeNumber?.toString()) ), 'N/A', - ].toSorted((a, b) => { + ].sort((a, b) => { if (a === 'N/A') return -1; if (b === 'N/A') return 1; return Number(a) - Number(b); @@ -559,7 +559,7 @@ const AllDashboardTable: React.FC = ({ query }) => { ), ...allCbcStatuses, ]), - ].toSorted((a, b) => statusOrderMap[a] - statusOrderMap[b]); + ].sort((a, b) => statusOrderMap[a] - statusOrderMap[b]); const externalStatuses = [ ...new Set([ @@ -568,7 +568,7 @@ const AllDashboardTable: React.FC = ({ query }) => { ), ...allCbcStatuses, ]), - ].toSorted((a, b) => statusOrderMap[a] - statusOrderMap[b]); + ].sort((a, b) => statusOrderMap[a] - statusOrderMap[b]); const uniqueLeads = [ ...new Set(allApplications.edges.map((edge) => edge.node.analystLead)), @@ -580,7 +580,7 @@ const AllDashboardTable: React.FC = ({ query }) => { ), ] .filter(filterOutNullishs) - .toSorted((a, b) => Number(a) - Number(b)); + .sort((a, b) => Number(a) - Number(b)); return [ { From db5ae03e00167fb1aad4d2fa7d2fa6b1e44bb0b2 Mon Sep 17 00:00:00 2001 From: R Ranathunga Date: Tue, 26 Nov 2024 08:27:45 -0800 Subject: [PATCH 02/21] fix: remove unwanted unsaved changes modal from RFI --- app/components/Analyst/RFI/RFI.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/components/Analyst/RFI/RFI.tsx b/app/components/Analyst/RFI/RFI.tsx index df8a7ae272..16471afaec 100644 --- a/app/components/Analyst/RFI/RFI.tsx +++ b/app/components/Analyst/RFI/RFI.tsx @@ -107,7 +107,7 @@ const RFI: React.FC = ({ rfiDataByRfiDataId, id }) => { formData={jsonData} noValidate tagName="div" - formContext={{ applicationId, rfiId: rowId }} + formContext={{ applicationId, rfiId: rowId, skipUnsavedWarning: true }} // Pass children to hide submit button // eslint-disable-next-line react/no-children-prop children From b1f6e37a76672d9a07ecc39b0dbb7dfd6c9f01cc Mon Sep 17 00:00:00 2001 From: R Ranathunga Date: Fri, 22 Nov 2024 13:13:21 -0800 Subject: [PATCH 03/21] fix: browser compatibility on toSorted --- app/components/AnalystDashboard/AllDashboard.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/components/AnalystDashboard/AllDashboard.tsx b/app/components/AnalystDashboard/AllDashboard.tsx index d9e448a531..88c3787171 100644 --- a/app/components/AnalystDashboard/AllDashboard.tsx +++ b/app/components/AnalystDashboard/AllDashboard.tsx @@ -536,7 +536,7 @@ const AllDashboardTable: React.FC = ({ query }) => { allApplications.edges.map((edge) => edge.node?.intakeNumber?.toString()) ), 'N/A', - ].toSorted((a, b) => { + ].sort((a, b) => { if (a === 'N/A') return -1; if (b === 'N/A') return 1; return Number(a) - Number(b); @@ -559,7 +559,7 @@ const AllDashboardTable: React.FC = ({ query }) => { ), ...allCbcStatuses, ]), - ].toSorted((a, b) => statusOrderMap[a] - statusOrderMap[b]); + ].sort((a, b) => statusOrderMap[a] - statusOrderMap[b]); const externalStatuses = [ ...new Set([ @@ -568,7 +568,7 @@ const AllDashboardTable: React.FC = ({ query }) => { ), ...allCbcStatuses, ]), - ].toSorted((a, b) => statusOrderMap[a] - statusOrderMap[b]); + ].sort((a, b) => statusOrderMap[a] - statusOrderMap[b]); const uniqueLeads = [ ...new Set(allApplications.edges.map((edge) => edge.node.analystLead)), @@ -580,7 +580,7 @@ const AllDashboardTable: React.FC = ({ query }) => { ), ] .filter(filterOutNullishs) - .toSorted((a, b) => Number(a) - Number(b)); + .sort((a, b) => Number(a) - Number(b)); return [ { From 377c12197681b1865fa8490c24e9321464c7b1af Mon Sep 17 00:00:00 2001 From: CCBC Service Account <116113628+ccbc-service-account@users.noreply.github.com> Date: Fri, 29 Nov 2024 17:06:24 +0000 Subject: [PATCH 04/21] chore: release v1.213.1 --- CHANGELOG.md | 6 ++++++ db/sqitch.plan | 1 + package.json | 2 +- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cf816199b7..e0214fa826 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [1.213.1](https://github.com/bcgov/CONN-CCBC-portal/compare/v1.213.0...v1.213.1) (2024-11-29) + +### Bug Fixes + +- browser compatibility on toSorted ([b1f6e37](https://github.com/bcgov/CONN-CCBC-portal/commit/b1f6e37a76672d9a07ecc39b0dbb7dfd6c9f01cc)) + # [1.213.0](https://github.com/bcgov/CONN-CCBC-portal/compare/v1.212.2...v1.213.0) (2024-11-27) ### Features diff --git a/db/sqitch.plan b/db/sqitch.plan index 6d817fb596..74ae9de9fa 100644 --- a/db/sqitch.plan +++ b/db/sqitch.plan @@ -748,3 +748,4 @@ tables/history_item_002_add_created_by 2024-11-13T19:45:04Z Rafael Solorzano <61 computed_columns/application_history [computed_columns/application_history@1.204.0] 2024-11-07T00:23:15Z Rafael Solorzano <61289255+rafasdc@users.noreply.github.com> # add history for application dependencies mutations/create_assessment_form [mutations/create_assessment_form@1.204.0] 2024-11-12T23:02:06Z Rafael Solorzano <61289255+rafasdc@users.noreply.github.com> # add case for application dependencies @1.213.0 2024-11-27T00:06:15Z CCBC Service Account # release v1.213.0 +@1.213.1 2024-11-29T17:06:22Z CCBC Service Account # release v1.213.1 diff --git a/package.json b/package.json index 4e5777a765..c2949e90c2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "CONN-CCBC-portal", - "version": "1.213.0", + "version": "1.213.1", "main": "index.js", "repository": "https://github.com/bcgov/CONN-CCBC-portal.git", "author": "Romer, Meherzad CITZ:EX ", From 331b8fed05a690e9679d0220b5f2c3cfda6b0b1d Mon Sep 17 00:00:00 2001 From: Anthony Bushara Date: Thu, 21 Nov 2024 10:56:35 -0500 Subject: [PATCH 05/21] chore: increase testing for assessments e2e --- .../assessments/financial-risk.cy.js | 42 +++++++++++-- .../[applicationId]/assessments/gis.cy.js | 44 +++++++++++-- .../[applicationId]/assessments/index.cy.js | 41 +++++++++++-- .../assessments/permitting.cy.js | 61 ++++++++++++++++--- .../assessments/project-management.cy.js | 49 +++++++++++++-- .../assessments/screening.cy.js | 51 +++++++++++++--- .../[applicationId]/assessments/setup.cy.js | 39 ++++++++++++ .../assessments/technical.cy.js | 56 ++++++++++++++--- 8 files changed, 338 insertions(+), 45 deletions(-) diff --git a/app/cypress/e2e/analyst/application/[applicationId]/assessments/financial-risk.cy.js b/app/cypress/e2e/analyst/application/[applicationId]/assessments/financial-risk.cy.js index 8a99bc65a1..73f730e597 100644 --- a/app/cypress/e2e/analyst/application/[applicationId]/assessments/financial-risk.cy.js +++ b/app/cypress/e2e/analyst/application/[applicationId]/assessments/financial-risk.cy.js @@ -1,12 +1,22 @@ /* eslint-disable import/extensions */ -import assessmentsSetup from './setup.cy.js'; +import assessmentsSetup, { + assessmentsSetupLoginAdmin, + assessmentsSetupLoginCbcAdmin, + assessmentsSetupLoginSuperAdmin, +} from './setup.cy.js'; -describe('The analyst financial risk assessment page', () => { - beforeEach(() => { - assessmentsSetup(); +const testLoad = (screenShotTitle, setupFunction) => { + setupFunction(); + cy.visit('/analyst/application/1/assessments/financial-risk'); + cy.contains('a', 'Financial Risk'); + cy.get('body').happoScreenshot({ + component: screenShotTitle, }); +}; - it('loads', () => { +describe('The analyst financial risk assessment page', () => { + it('loads with analyst', () => { + assessmentsSetup(); cy.visit('/analyst/application/1/assessments/financial-risk'); cy.contains('a', 'Financial Risk'); cy.get('body').happoScreenshot({ @@ -14,7 +24,29 @@ describe('The analyst financial risk assessment page', () => { }); }); + it('loads with cbcAdmin', () => { + testLoad( + 'Analyst financial risk assessment page with CBC Admin', + assessmentsSetupLoginCbcAdmin + ); + }); + + it('loads with admin', () => { + testLoad( + 'Analyst financial risk assessment page with ccbc admin', + assessmentsSetupLoginAdmin + ); + }); + + it('loads with super admin', () => { + testLoad( + 'Analyst financial risk assessment page with super admin', + assessmentsSetupLoginSuperAdmin + ); + }); + it('Filled page and saved', () => { + assessmentsSetup(); cy.visit('/analyst/application/1/assessments/financial-risk'); cy.contains('a', 'Financial Risk'); cy.wait('@graphql'); diff --git a/app/cypress/e2e/analyst/application/[applicationId]/assessments/gis.cy.js b/app/cypress/e2e/analyst/application/[applicationId]/assessments/gis.cy.js index b40c7c53db..b7cb9884bf 100644 --- a/app/cypress/e2e/analyst/application/[applicationId]/assessments/gis.cy.js +++ b/app/cypress/e2e/analyst/application/[applicationId]/assessments/gis.cy.js @@ -1,12 +1,22 @@ /* eslint-disable import/extensions */ -import assessmentsSetup from './setup.cy.js'; +import assessmentsSetup, { + assessmentsSetupLoginAdmin, + assessmentsSetupLoginCbcAdmin, + assessmentsSetupLoginSuperAdmin, +} from './setup.cy.js'; -describe('The analyst technical assessment page', () => { - beforeEach(() => { - assessmentsSetup(); +const testLoad = (screenShotTitle, setupFunction) => { + setupFunction(); + cy.visit('/analyst/application/1/assessments/gis'); + cy.contains('a', 'GIS'); + cy.get('body').happoScreenshot({ + component: screenShotTitle, }); +}; - it('loads', () => { +describe('The analyst GIS assessment page', () => { + it('loads with analyst', () => { + assessmentsSetup(); cy.visit('/analyst/application/1/assessments/gis'); cy.contains('a', 'GIS'); cy.get('body').happoScreenshot({ @@ -14,7 +24,29 @@ describe('The analyst technical assessment page', () => { }); }); - it('Filled GIS Assessment Page', () => { + it('loads with cbcAdmin', () => { + testLoad( + 'Analyst GIS assessment page with CBC Admin', + assessmentsSetupLoginCbcAdmin + ); + }); + + it('loads with admin', () => { + testLoad( + 'Analyst GIS assessment page with admin', + assessmentsSetupLoginAdmin + ); + }); + + it('loads with super admin', () => { + testLoad( + 'Analyst GIS assessment page with super admin', + assessmentsSetupLoginSuperAdmin + ); + }); + + it('Filled GIS Assessment Page and saved', () => { + assessmentsSetup(); cy.visit('/analyst/application/1/assessments/gis'); cy.contains('a', 'GIS'); cy.wait('@graphql'); diff --git a/app/cypress/e2e/analyst/application/[applicationId]/assessments/index.cy.js b/app/cypress/e2e/analyst/application/[applicationId]/assessments/index.cy.js index 50bc58edf2..342ee60080 100644 --- a/app/cypress/e2e/analyst/application/[applicationId]/assessments/index.cy.js +++ b/app/cypress/e2e/analyst/application/[applicationId]/assessments/index.cy.js @@ -1,16 +1,47 @@ /* eslint-disable import/extensions */ -import assessmentsSetup from './setup.cy.js'; +import assessmentsSetup, { + assessmentsSetupLoginAdmin, + assessmentsSetupLoginCbcAdmin, + assessmentsSetupLoginSuperAdmin, +} from './setup.cy.js'; -describe('The analyst assessments dashboard view', () => { - beforeEach(() => { - assessmentsSetup(); +const testLoad = (screenShotTitle, setupFunction) => { + setupFunction(); + cy.visit('/analyst/application/1/assessments'); + cy.contains('h2', 'Assessments'); + cy.get('body').happoScreenshot({ + component: screenShotTitle, }); +}; - it('loads', () => { +describe('The analyst assessments dashboard view', () => { + it('loads with analyst', () => { + assessmentsSetup(); cy.visit('/analyst/application/1/assessments'); cy.contains('h2', 'Assessments'); cy.get('body').happoScreenshot({ component: 'Analyst assessments dashboard', }); }); + + it('loads with CBC Admin', () => { + testLoad( + 'Analyst assessments dashboard with CBC Admin', + assessmentsSetupLoginCbcAdmin + ); + }); + + it('loads with Admin', () => { + testLoad( + 'Analyst assessments dashboard with Admin', + assessmentsSetupLoginAdmin + ); + }); + + it('loads with Super Admin', () => { + testLoad( + 'Analyst assessments dashboard with Super Admin', + assessmentsSetupLoginSuperAdmin + ); + }); }); diff --git a/app/cypress/e2e/analyst/application/[applicationId]/assessments/permitting.cy.js b/app/cypress/e2e/analyst/application/[applicationId]/assessments/permitting.cy.js index 1d90adea95..f009227553 100644 --- a/app/cypress/e2e/analyst/application/[applicationId]/assessments/permitting.cy.js +++ b/app/cypress/e2e/analyst/application/[applicationId]/assessments/permitting.cy.js @@ -1,12 +1,28 @@ /* eslint-disable import/extensions */ -import assessmentsSetup from './setup.cy.js'; +import assessmentsSetup, { + assessmentsSetupLoginAdmin, + assessmentsSetupLoginCbcAdmin, + assessmentsSetupLoginSuperAdmin, +} from './setup.cy.js'; -describe('The analyst permitting assessment page', () => { - beforeEach(() => { - assessmentsSetup(); +/** + * Reusable function to test loading of the permitting assessment page + * @param {string} screenShotTitle - Title for the screenshot + * @param {Function} setupFunction - Setup function for the specific user role + */ +const testLoad = (screenShotTitle, setupFunction) => { + setupFunction(); + cy.visit('/analyst/application/1/assessments/permitting'); + cy.contains('a', 'Permitting'); + cy.get('body').happoScreenshot({ + component: screenShotTitle, }); +}; - it('loads', () => { +describe('The analyst permitting assessment page', () => { + // Test loading for Analyst role + it('loads with analyst', () => { + assessmentsSetup(); cy.visit('/analyst/application/1/assessments/permitting'); cy.contains('a', 'Permitting'); cy.get('body').happoScreenshot({ @@ -14,15 +30,42 @@ describe('The analyst permitting assessment page', () => { }); }); - it('Filled permitting assessment page', () => { + // Test loading for CBC Admin role + it('loads with CBC Admin', () => { + testLoad( + 'Permitting assessment page with CBC Admin', + assessmentsSetupLoginCbcAdmin + ); + }); + + // Test loading for Admin role + it('loads with Admin', () => { + testLoad( + 'Permitting assessment page with Admin', + assessmentsSetupLoginAdmin + ); + }); + + // Test loading for Super Admin role + it('loads with Super Admin', () => { + testLoad( + 'Permitting assessment page with Super Admin', + assessmentsSetupLoginSuperAdmin + ); + }); + + // Test for filling and saving the permitting assessment form (Analyst role) + it('fills and saves the permitting assessment page', () => { + assessmentsSetup(); cy.visit('/analyst/application/1/assessments/permitting'); cy.contains('a', 'Permitting'); cy.wait('@graphql'); cy.get('select[id="root_assignedTo"]').select('Meherzad Romer'); cy.get('input[id="root_targetDate"]').invoke('val', '2023-03-10'); - cy.get('input[id="root_decision-0"').parent().click(); - cy.get('input[id="root_decision-1"').parent().click(); - cy.get('input[id="root_decision-2"').parent().click(); + cy.get('input[id="root_decision-0"]').parent().click(); + cy.get('input[id="root_decision-1"]').parent().click(); + cy.get('input[id="root_decision-2"]').parent().click(); + cy.get('#root_notesAndConsiderations').type( 'These are some notes and considerations' ); diff --git a/app/cypress/e2e/analyst/application/[applicationId]/assessments/project-management.cy.js b/app/cypress/e2e/analyst/application/[applicationId]/assessments/project-management.cy.js index 946d97bf9b..b7149a8c68 100644 --- a/app/cypress/e2e/analyst/application/[applicationId]/assessments/project-management.cy.js +++ b/app/cypress/e2e/analyst/application/[applicationId]/assessments/project-management.cy.js @@ -1,12 +1,23 @@ /* eslint-disable import/extensions */ -import assessmentsSetup from './setup.cy.js'; +import assessmentsSetup, { + assessmentsSetupLoginAdmin, + assessmentsSetupLoginCbcAdmin, + assessmentsSetupLoginSuperAdmin, +} from './setup.cy.js'; -describe('The analyst project management assessment page', () => { - beforeEach(() => { - assessmentsSetup(); +const testLoad = (screenShotTitle, setupFunction) => { + setupFunction(); + cy.visit('/analyst/application/1/assessments/project-management'); + cy.contains('a', 'Project Management'); + cy.get('body').happoScreenshot({ + component: screenShotTitle, }); +}; - it('loads', () => { +describe('The analyst project management assessment page', () => { + // Test loading for Analyst role + it('loads with analyst', () => { + assessmentsSetup(); cy.visit('/analyst/application/1/assessments/project-management'); cy.contains('a', 'Project Management'); cy.get('body').happoScreenshot({ @@ -14,7 +25,33 @@ describe('The analyst project management assessment page', () => { }); }); - it('Filled Project Management Page', () => { + // Test loading for CBC Admin role + it('loads with CBC Admin', () => { + testLoad( + 'Project Management assessment page with CBC Admin', + assessmentsSetupLoginCbcAdmin + ); + }); + + // Test loading for Admin role + it('loads with Admin', () => { + testLoad( + 'Project Management assessment page with Admin', + assessmentsSetupLoginAdmin + ); + }); + + // Test loading for Super Admin role + it('loads with Super Admin', () => { + testLoad( + 'Project Management assessment page with Super Admin', + assessmentsSetupLoginSuperAdmin + ); + }); + + // Test for filling and saving the project management assessment form (Analyst role) + it('fills and saves the project management assessment page', () => { + assessmentsSetup(); cy.visit('/analyst/application/1/assessments/project-management'); cy.contains('a', 'Project Management'); cy.wait('@graphql'); diff --git a/app/cypress/e2e/analyst/application/[applicationId]/assessments/screening.cy.js b/app/cypress/e2e/analyst/application/[applicationId]/assessments/screening.cy.js index 6cc262feb4..e496ab0c3b 100644 --- a/app/cypress/e2e/analyst/application/[applicationId]/assessments/screening.cy.js +++ b/app/cypress/e2e/analyst/application/[applicationId]/assessments/screening.cy.js @@ -1,12 +1,23 @@ /* eslint-disable import/extensions */ -import assessmentsSetup from './setup.cy.js'; +import assessmentsSetup, { + assessmentsSetupLoginAdmin, + assessmentsSetupLoginCbcAdmin, + assessmentsSetupLoginSuperAdmin, +} from './setup.cy.js'; -describe('The analyst screening assessment page', () => { - beforeEach(() => { - assessmentsSetup(); +const testLoad = (screenShotTitle, setupFunction) => { + setupFunction(); + cy.visit('/analyst/application/1/assessments/screening'); + cy.contains('a', 'Screening'); + cy.get('body').happoScreenshot({ + component: screenShotTitle, }); +}; - it('loads', () => { +describe('The analyst screening assessment page', () => { + // Test loading for Analyst role + it('loads with analyst', () => { + assessmentsSetup(); cy.visit('/analyst/application/1/assessments/screening'); cy.contains('a', 'Screening'); cy.get('body').happoScreenshot({ @@ -14,7 +25,33 @@ describe('The analyst screening assessment page', () => { }); }); - it('Filled Screening Page', () => { + // Test loading for CBC Admin role + it('loads with CBC Admin', () => { + testLoad( + 'Screening assessment page with CBC Admin', + assessmentsSetupLoginCbcAdmin + ); + }); + + // Test loading for Admin role + it('loads with Admin', () => { + testLoad( + 'Screening assessment page with Admin', + assessmentsSetupLoginAdmin + ); + }); + + // Test loading for Super Admin role + it('loads with Super Admin', () => { + testLoad( + 'Screening assessment page with Super Admin', + assessmentsSetupLoginSuperAdmin + ); + }); + + // Test for filling and saving the screening assessment form (Analyst role) + it('fills and saves the screening assessment page', () => { + assessmentsSetup(); cy.visit('/analyst/application/1/assessments/screening'); cy.contains('a', 'Screening'); cy.wait('@graphql'); @@ -24,7 +61,7 @@ describe('The analyst screening assessment page', () => { cy.get('input[id="root_decision-1"]').parent().click(); cy.get('input[id="root_contestingMap-0"]').parent().click(); cy.contains('button', /^Save$/).click(); - cy.contains('button', 'Saved'); + cy.contains('button', 'Saved').should('exist'); cy.visit('/analyst/application/1/assessments/screening'); cy.get('body').happoScreenshot({ component: 'Filled Analyst screening assessment page', diff --git a/app/cypress/e2e/analyst/application/[applicationId]/assessments/setup.cy.js b/app/cypress/e2e/analyst/application/[applicationId]/assessments/setup.cy.js index 0da1fb27ab..845396aa9d 100644 --- a/app/cypress/e2e/analyst/application/[applicationId]/assessments/setup.cy.js +++ b/app/cypress/e2e/analyst/application/[applicationId]/assessments/setup.cy.js @@ -11,4 +11,43 @@ const assessmentsSetup = () => { cy.intercept('POST', '/graphql').as('graphql'); }; +export const assessmentsSetupLoginAdmin = () => { + cy.mockLogin('ccbc_admin'); + const mockedDateString = '2022-10-10'; + const mockedDate = new Date(mockedDateString); + cy.useMockedTime(mockedDate); + cy.sqlFixture('e2e/reset_db'); + cy.sqlFixture('e2e/001_intake'); + cy.sqlFixture('e2e/001_application'); + cy.sqlFixture('e2e/001_application_received'); + cy.sqlFixture('e2e/001_analyst'); + cy.intercept('POST', '/graphql').as('graphql'); +}; + +export const assessmentsSetupLoginSuperAdmin = () => { + cy.mockLogin('super_admin'); + const mockedDateString = '2022-10-10'; + const mockedDate = new Date(mockedDateString); + cy.useMockedTime(mockedDate); + cy.sqlFixture('e2e/reset_db'); + cy.sqlFixture('e2e/001_intake'); + cy.sqlFixture('e2e/001_application'); + cy.sqlFixture('e2e/001_application_received'); + cy.sqlFixture('e2e/001_analyst'); + cy.intercept('POST', '/graphql').as('graphql'); +}; + +export const assessmentsSetupLoginCbcAdmin = () => { + cy.mockLogin('cbc_admin'); + const mockedDateString = '2022-10-10'; + const mockedDate = new Date(mockedDateString); + cy.useMockedTime(mockedDate); + cy.sqlFixture('e2e/reset_db'); + cy.sqlFixture('e2e/001_intake'); + cy.sqlFixture('e2e/001_application'); + cy.sqlFixture('e2e/001_application_received'); + cy.sqlFixture('e2e/001_analyst'); + cy.intercept('POST', '/graphql').as('graphql'); +}; + export default assessmentsSetup; diff --git a/app/cypress/e2e/analyst/application/[applicationId]/assessments/technical.cy.js b/app/cypress/e2e/analyst/application/[applicationId]/assessments/technical.cy.js index e3600a1596..cc4bd1e9e8 100644 --- a/app/cypress/e2e/analyst/application/[applicationId]/assessments/technical.cy.js +++ b/app/cypress/e2e/analyst/application/[applicationId]/assessments/technical.cy.js @@ -1,12 +1,28 @@ /* eslint-disable import/extensions */ -import assessmentsSetup from './setup.cy.js'; +import assessmentsSetup, { + assessmentsSetupLoginAdmin, + assessmentsSetupLoginCbcAdmin, + assessmentsSetupLoginSuperAdmin, +} from './setup.cy.js'; -describe('The analyst technical assessment page', () => { - beforeEach(() => { - assessmentsSetup(); +/** + * Reusable function to test loading of the technical assessment page + * @param {string} screenShotTitle - Title for the screenshot + * @param {Function} setupFunction - Setup function for the specific user role + */ +const testLoad = (screenShotTitle, setupFunction) => { + setupFunction(); + cy.visit('/analyst/application/1/assessments/technical'); + cy.contains('a', 'Technical'); + cy.get('body').happoScreenshot({ + component: screenShotTitle, }); +}; - it('loads', () => { +describe('The analyst technical assessment page', () => { + // Test loading for Analyst role + it('loads with analyst', () => { + assessmentsSetup(); cy.visit('/analyst/application/1/assessments/technical'); cy.contains('a', 'Technical'); cy.get('body').happoScreenshot({ @@ -14,7 +30,33 @@ describe('The analyst technical assessment page', () => { }); }); - it('Filled Technical Assessment Page', () => { + // Test loading for CBC Admin role + it('loads with CBC Admin', () => { + testLoad( + 'Technical assessment page with CBC Admin', + assessmentsSetupLoginCbcAdmin + ); + }); + + // Test loading for Admin role + it('loads with Admin', () => { + testLoad( + 'Technical assessment page with Admin', + assessmentsSetupLoginAdmin + ); + }); + + // Test loading for Super Admin role + it('loads with Super Admin', () => { + testLoad( + 'Technical assessment page with Super Admin', + assessmentsSetupLoginSuperAdmin + ); + }); + + // Test for filling and saving the technical assessment form (Analyst role) + it('fills and saves the technical assessment page', () => { + assessmentsSetup(); cy.visit('/analyst/application/1/assessments/technical'); cy.contains('a', 'Technical'); cy.wait('@graphql'); @@ -23,7 +65,7 @@ describe('The analyst technical assessment page', () => { cy.get('input[id="root_nextStep-1"]').parent().click(); cy.get('input[id="root_decision-1"]').parent().click(); cy.contains('button', /^Save$/).click(); - cy.contains('button', 'Saved'); + cy.contains('button', 'Saved').should('exist'); cy.visit('/analyst/application/1/assessments/technical'); cy.get('body').happoScreenshot({ component: 'Filled Analyst Technical Assessment Page', From b2ee4a2a6bbe94399d7aed36880fee5e111540dc Mon Sep 17 00:00:00 2001 From: Anthony Bushara Date: Wed, 27 Nov 2024 20:34:22 -0500 Subject: [PATCH 06/21] test(e2e): extra testing for roles on other pages --- .../analyst/application/[applicationId].cy.js | 38 +- .../application/[applicationId]/history.cy.js | 149 ++-- .../application/[applicationId]/project.cy.js | 720 +++++++++--------- .../[applicationId]/rfi/index.cy.js | 82 +- .../[applicationId]/rfi/setup.cy.js | 41 +- app/cypress/e2e/analyst/cbc/[cbcId].cy.js | 42 +- app/cypress/e2e/analyst/dashboard.cy.js | 106 ++- 7 files changed, 670 insertions(+), 508 deletions(-) diff --git a/app/cypress/e2e/analyst/application/[applicationId].cy.js b/app/cypress/e2e/analyst/application/[applicationId].cy.js index 14d94194aa..1266eabbfe 100644 --- a/app/cypress/e2e/analyst/application/[applicationId].cy.js +++ b/app/cypress/e2e/analyst/application/[applicationId].cy.js @@ -1,19 +1,27 @@ +const setups = ['ccbc_analyst', 'ccbc_admin', 'super_admin', 'cbc_admin']; + describe('The analyst application view', () => { - beforeEach(() => { - cy.mockLogin('ccbc_analyst'); - const mockedDateString = '2022-10-10'; - const mockedDate = new Date(mockedDateString); - cy.useMockedTime(mockedDate); - cy.sqlFixture('e2e/reset_db'); - cy.sqlFixture('e2e/001_intake'); - cy.sqlFixture('e2e/001_application'); - cy.sqlFixture('e2e/001_application_received'); - cy.sqlFixture('e2e/001_analyst'); - }); + setups.forEach((role) => { + describe(`As ${role}`, () => { + beforeEach(() => { + cy.mockLogin(role); + const mockedDateString = '2022-10-10'; + const mockedDate = new Date(mockedDateString); + cy.useMockedTime(mockedDate); + cy.sqlFixture('e2e/reset_db'); + cy.sqlFixture('e2e/001_intake'); + cy.sqlFixture('e2e/001_application'); + cy.sqlFixture('e2e/001_application_received'); + cy.sqlFixture('e2e/001_analyst'); + }); - it('loads', () => { - cy.visit('/analyst/application/1'); - cy.contains('h1', 'Test application'); - cy.get('body').happoScreenshot({ component: 'Analyst application view' }); + it('loads', () => { + cy.visit('/analyst/application/1'); + cy.contains('h1', 'Test application'); + cy.get('body').happoScreenshot({ + component: `Analyst application view - ${role}`, + }); + }); + }); }); }); diff --git a/app/cypress/e2e/analyst/application/[applicationId]/history.cy.js b/app/cypress/e2e/analyst/application/[applicationId]/history.cy.js index ab09d93f30..a8ebd719dc 100644 --- a/app/cypress/e2e/analyst/application/[applicationId]/history.cy.js +++ b/app/cypress/e2e/analyst/application/[applicationId]/history.cy.js @@ -1,81 +1,92 @@ -describe('The analyst history page', () => { - beforeEach(() => { - cy.mockLogin('ccbc_analyst'); - const mockedDateString = '2022-10-10'; - const mockedDate = new Date(mockedDateString); - cy.useMockedTime(mockedDate); - cy.sqlFixture('e2e/reset_db'); - cy.sqlFixture('e2e/001_intake'); - cy.sqlFixture('e2e/001_application'); - cy.sqlFixture('e2e/001_application_received'); - cy.sqlFixture('e2e/001_rfi'); - cy.sqlFixture('e2e/001_history'); - cy.intercept('POST', '/graphql').as('graphql'); - }); +const setup = (role) => { + cy.mockLogin(role); + const mockedDateString = '2022-10-10'; + const mockedDate = new Date(mockedDateString); + cy.useMockedTime(mockedDate); + cy.sqlFixture('e2e/reset_db'); + cy.sqlFixture('e2e/001_intake'); + cy.sqlFixture('e2e/001_application'); + cy.sqlFixture('e2e/001_application_received'); + cy.sqlFixture('e2e/001_rfi'); + cy.sqlFixture('e2e/001_history'); + cy.intercept('POST', '/graphql').as('graphql'); +}; - it('loads', () => { - cy.visit('/analyst/application/1/history'); +const setups = ['ccbc_analyst', 'ccbc_admin', 'cbc_admin', 'super_admin']; +describe('The application history page', () => { + setups.forEach((role) => { + describe(`as ${role}'`, () => { + beforeEach(() => { + setup(role); + }); - cy.contains('h2', 'History'); + it('loads', () => { + cy.visit('/analyst/application/1/history'); - // Edit application - cy.contains(/Annie Analyst edited the Application/); - cy.contains('Reason For Change: e2e testing', { matchCase: false }); + cy.contains('h2', 'History'); - // Change request - cy.contains(/Annie Analyst created a Change Request/); - cy.contains('Updated Statement of Work Excel'); - cy.contains('CCBC-010001-sow_excel.xlsx'); + // Edit application + cy.contains(/Annie Analyst edited the Application/); + cy.contains('Reason For Change: e2e testing', { matchCase: false }); - // Project Information (SoW form) - cy.contains(/Annie Analyst saved the Project information/, { - matchCase: false, - }); - cy.contains('Statement of Work Excel'); - cy.contains('SOW Wireless Table'); - cy.contains('Funding agreement'); - cy.contains('Finalized spatial data'); + // Change request + cy.contains(/Annie Analyst created a Change Request/); + cy.contains('Updated Statement of Work Excel'); + cy.contains('CCBC-010001-sow_excel.xlsx'); - // Announcement - cy.contains('announcement'); + // Project Information (SoW form) + cy.contains(/Annie Analyst saved the Project information/, { + matchCase: false, + }); + cy.contains('Statement of Work Excel'); + cy.contains('SOW Wireless Table'); + cy.contains('Funding agreement'); + cy.contains('Finalized spatial data'); - // RFI - cy.contains(/Annie Analyst saved RFI-CCBC-010001-1/); - cy.contains('RFI type'); - cy.contains('Missing files or information'); - cy.contains('Due by'); - cy.contains('Logical Network Diagram requested'); - cy.contains('Template 1 - Eligibility and Impacts Calculator requested'); - cy.contains('Template 6 - Community Benefits requested'); + // Announcement + cy.contains('announcement'); - // Assessments - cy.contains(/Annie Analyst updated the Permitting assessment/, { - matchCase: false, - }); - cy.contains(/Annie Analyst updated the Project Management assessment/, { - matchCase: false, - }); - cy.contains(/Annie Analyst updated the Financial Risk assessment/, { - matchCase: false, - }); - cy.contains(/Annie Analyst updated the GIS assessment/, { - matchCase: false, - }); - cy.contains(/Annie Analyst updated the Technical assessment/, { - matchCase: false, - }); - cy.contains(/Annie Analyst updated the Screening assessment/, { - matchCase: false, - }); + // RFI + cy.contains(/Annie Analyst saved RFI-CCBC-010001-1/); + cy.contains('RFI type'); + cy.contains('Missing files or information'); + cy.contains('Due by'); + cy.contains('Logical Network Diagram requested'); + cy.contains( + 'Template 1 - Eligibility and Impacts Calculator requested' + ); + cy.contains('Template 6 - Community Benefits requested'); - // Status - cy.contains( - /Annie Analyst changed the Internal Status to Conditionally approved/, - { - matchCase: false, - } - ); + // Assessments + cy.contains(/Annie Analyst updated the Permitting assessment/, { + matchCase: false, + }); + cy.contains(/Annie Analyst updated the Project Management assessment/, { + matchCase: false, + }); + cy.contains(/Annie Analyst updated the Financial Risk assessment/, { + matchCase: false, + }); + cy.contains(/Annie Analyst updated the GIS assessment/, { + matchCase: false, + }); + cy.contains(/Annie Analyst updated the Technical assessment/, { + matchCase: false, + }); + cy.contains(/Annie Analyst updated the Screening assessment/, { + matchCase: false, + }); - cy.contains(/The application was Received/, { matchCase: false }); + // Status + cy.contains( + /Annie Analyst changed the Internal Status to Conditionally approved/, + { + matchCase: false, + } + ); + + cy.contains(/The application was Received/, { matchCase: false }); + }); + }); }); }); diff --git a/app/cypress/e2e/analyst/application/[applicationId]/project.cy.js b/app/cypress/e2e/analyst/application/[applicationId]/project.cy.js index a69d13964f..37438d2ed2 100644 --- a/app/cypress/e2e/analyst/application/[applicationId]/project.cy.js +++ b/app/cypress/e2e/analyst/application/[applicationId]/project.cy.js @@ -1,354 +1,394 @@ -describe('The analyst application view', () => { - beforeEach(() => { - cy.mockLogin('ccbc_analyst'); - const mockedDateString = '2022-10-10'; - const mockedDate = new Date(mockedDateString); - cy.useMockedTime(mockedDate); - cy.sqlFixture('e2e/reset_db'); - cy.sqlFixture('e2e/001_intake'); - cy.sqlFixture('e2e/001_application'); - cy.sqlFixture('e2e/001_application_received'); - cy.intercept('POST', '/graphql').as('graphql'); - - cy.intercept('POST', '/api/analyst/sow/1/CCBC-010001/*/?validate=true', { - statusCode: 200, - body: {}, - }).as('sow-upload-validate'); - - cy.intercept('POST', '/api/analyst/community-report/1/*/?validate=true', { - statusCode: 200, - body: {}, - }).as('community-report-validate'); - - cy.intercept( - 'POST', - '/api/analyst/milestone/1/CCBC-010001/*/?validate=true', - { - statusCode: 200, - body: {}, - } - ).as('milestone-validate'); - - cy.intercept('POST', '/api/analyst/claims/1/CCBC-010001/*/*/?validate=*', { - statusCode: 200, - body: {}, - }).as('claims-validate'); - }); - - // We should be able to clean up a lot of these cy.wait() calls (especially the datepicker ones) once we upgrade to cypress 12. - // These have been added to mitigate detached DOM errors. - - it('loads', () => { - cy.visit('/analyst/application/1/project'); - - cy.contains('h2', 'Conditional approval'); - - cy.wait(500); - - cy.get('body').happoScreenshot({ component: 'Conditional approval form' }); - // Province decision section - cy.get('select[id="root_decision_ministerDecision"]').select('Approved'); - - cy.get('[id="root_decision_ministerDate"]') - .parent() - .find('.MuiButtonBase-root') - .click(); - cy.get('button').contains('1').click(); - - cy.get('select[id="root_decision_ministerAnnouncement"]').select( - 'Announce immediately' - ); - cy.get('[id="root_decision_provincialRequested"]').type(10); - - // ISED decision section - cy.get('select[id="root_isedDecisionObj_isedDecision"]').select('Approved'); - - cy.get('[id="root_isedDecisionObj_isedDate"]') - .parent() - .find('.MuiButtonBase-root') - .click(); - cy.wait(200); - cy.get('button').contains('1').click(); - - cy.contains('h2', 'Announcements'); - cy.get('select[id="root_isedDecisionObj_isedAnnouncement"]').select( - 'Announce immediately' - ); - cy.get('[id="root_isedDecisionObj_federalRequested"]').type(120); - - // Minister decision, letter and response file upload - cy.get('[id="root_letterOfApproval_letterOfApprovalUpload-btn"]').click(); - cy.get('[data-testid=file-test]') - .first() - .selectFile('cypress/fixtures/doc.txt', { force: true }); - cy.wait(2000); - cy.contains('button', 'doc.txt'); - - // Applicant response - cy.get('[id="root_letterOfApproval_letterOfApprovalDateSent"]') - .parent() - .find('.MuiButtonBase-root') - .click(); - cy.wait(200); - cy.get('button').contains('1').click(); - - cy.get('select[id="root_response_applicantResponse"]').select('Accepted'); - - cy.get('select[id="root_response_statusApplicantSees"]').select( - 'Conditionally Approved' - ); - - // Save conditional approval - cy.get('#conditional-approval-save-button').click(); - - cy.get('button').contains('Yes, change it').click(); - cy.wait('@graphql'); - - // Announcements test - - // Open accordion - cy.get('[data-testid=accordion-icon]').parent().eq(1).click(); - cy.get('body').click(); - - cy.get('button').contains('Add announcement').click(); - - cy.get('select[id="root_announcementType"]').select('Primary'); - - cy.get('[id="root_announcementUrl"]').type('www.e2e-testing.com'); - - cy.get('[id="root_announcementDate"]') - .parent() - .find('.MuiButtonBase-root') - .click(); - cy.wait(200); - cy.get('button').contains('1').click(); - - cy.get('body').happoScreenshot({ component: 'Announcements form' }); - - // Save announcement - cy.get('#announcements-save-button').click(); - - // Add secondary announcement - cy.get('button').contains('Add announcement').click(); +const setups = ['ccbc_analyst', 'ccbc_admin', 'super_admin', 'cbc_admin']; - cy.get('select[id="root_announcementType"]').select('Secondary'); - - cy.get('[id="root_announcementUrl"]').type('www.e2e-testing.com'); - - cy.get('[id="root_announcementDate"]') - .parent() - .find('.MuiButtonBase-root') - .click(); - cy.wait(200); - cy.get('button').contains('1').click(); - - // Save announcement - cy.get('#announcements-save-button').click(); - - cy.wait('@graphql'); - - // SoW/Change request form - cy.contains('h2', 'Funding agreement, statement of work, & map'); - - cy.get('[id="root_hasFundingAgreementBeenSigned-0"]') - .parent() - .click({ force: true }); - - cy.get('[id="root_dateFundingAgreementSigned"]') - .parent() - .find('.MuiButtonBase-root') - .click(); - cy.wait(200); - cy.get('button').contains('1').click(); - - // Funding agreement upload - cy.get('[id="root_fundingAgreementUpload-btn"]').click(); - cy.get('[data-testid=file-test]') - .first() - .selectFile('cypress/fixtures/doc.txt', { force: true }); - cy.wait(2000); - cy.contains('button', 'doc.txt'); - - // Statement of work excel import - - cy.get('[id="root_statementOfWorkUpload-btn"]').click(); - cy.get('[data-testid=file-test]') - .eq(1) - .selectFile('cypress/fixtures/mock_excel.xlsx', { - force: true, +describe('The analyst application view', () => { + setups.forEach((role) => { + describe(`As ${role}`, () => { + beforeEach(() => { + cy.mockLogin('ccbc_analyst'); + const mockedDateString = '2022-10-10'; + const mockedDate = new Date(mockedDateString); + cy.useMockedTime(mockedDate); + cy.sqlFixture('e2e/reset_db'); + cy.sqlFixture('e2e/001_intake'); + cy.sqlFixture('e2e/001_application'); + cy.sqlFixture('e2e/001_application_received'); + cy.intercept('POST', '/graphql').as('graphql'); + + cy.intercept( + 'POST', + '/api/analyst/sow/1/CCBC-010001/*/?validate=true', + { + statusCode: 200, + body: {}, + } + ).as('sow-upload-validate'); + + cy.intercept( + 'POST', + '/api/analyst/community-report/1/*/?validate=true', + { + statusCode: 200, + body: {}, + } + ).as('community-report-validate'); + + cy.intercept( + 'POST', + '/api/analyst/milestone/1/CCBC-010001/*/?validate=true', + { + statusCode: 200, + body: {}, + } + ).as('milestone-validate'); + + cy.intercept( + 'POST', + '/api/analyst/claims/1/CCBC-010001/*/*/?validate=*', + { + statusCode: 200, + body: {}, + } + ).as('claims-validate'); }); - cy.wait('@sow-upload-validate', { timeout: 50000 }); - cy.contains('button', 'mock_excel.xlsx'); - cy.get('body').happoScreenshot({ component: 'Statement of work form' }); + // We should be able to clean up a lot of these cy.wait() calls (especially the datepicker ones) once we upgrade to cypress 12. + // These have been added to mitigate detached DOM errors. + + it('loads', () => { + cy.visit('/analyst/application/1/project'); + + cy.contains('h2', 'Conditional approval'); + + cy.wait(500); - // Save statement of work - cy.contains('Save & Import Data').click(); + cy.get('body').happoScreenshot({ + component: `Conditional approval form - ${role}`, + }); + // Province decision section + cy.get('select[id="root_decision_ministerDecision"]').select( + 'Approved' + ); + + cy.get('[id="root_decision_ministerDate"]') + .parent() + .find('.MuiButtonBase-root') + .click(); + cy.get('button').contains('1').click(); - cy.wait(2000); + cy.get('select[id="root_decision_ministerAnnouncement"]').select( + 'Announce immediately' + ); + cy.get('[id="root_decision_provincialRequested"]').type(10); - // Add change request + // ISED decision section + cy.get('select[id="root_isedDecisionObj_isedDecision"]').select( + 'Approved' + ); - // Open accordion - cy.get('[data-testid=accordion-icon]').eq(2).parent().click(); + cy.get('[id="root_isedDecisionObj_isedDate"]') + .parent() + .find('.MuiButtonBase-root') + .click(); + cy.wait(200); + cy.get('button').contains('1').click(); + + cy.contains('h2', 'Announcements'); + cy.get('select[id="root_isedDecisionObj_isedAnnouncement"]').select( + 'Announce immediately' + ); + cy.get('[id="root_isedDecisionObj_federalRequested"]').type(120); + + // Minister decision, letter and response file upload + cy.get( + '[id="root_letterOfApproval_letterOfApprovalUpload-btn"]' + ).click(); + cy.get('[data-testid=file-test]') + .first() + .selectFile('cypress/fixtures/doc.txt', { force: true }); + cy.wait(2000); + cy.contains('button', 'doc.txt'); + + // Applicant response + cy.get('[id="root_letterOfApproval_letterOfApprovalDateSent"]') + .parent() + .find('.MuiButtonBase-root') + .click(); + cy.wait(200); + cy.get('button').contains('1').click(); + + cy.get('select[id="root_response_applicantResponse"]').select( + 'Accepted' + ); + + cy.get('select[id="root_response_statusApplicantSees"]').select( + 'Conditionally Approved' + ); - cy.get('button').contains('Add change request').click(); + // Save conditional approval + cy.get('#conditional-approval-save-button').click(); - cy.get('[id="root_amendmentNumber"]').type(1); + cy.get('button').contains('Yes, change it').click(); + cy.wait('@graphql'); + + // Announcements test + + // Open accordion + cy.get('[data-testid=accordion-icon]').parent().eq(1).click(); + cy.get('body').click(); + + cy.get('button').contains('Add announcement').click(); + + cy.get('select[id="root_announcementType"]').select('Primary'); + + cy.get('[id="root_announcementUrl"]').type('www.e2e-testing.com'); + + cy.get('[id="root_announcementDate"]') + .parent() + .find('.MuiButtonBase-root') + .click(); + cy.wait(200); + cy.get('button').contains('1').click(); - cy.get('[id="root_dateRequested"]') - .parent() - .find('.MuiButtonBase-root') - .click(); - cy.wait(200); - cy.get('button').contains('1').click(); - - cy.get('[id="root_dateApproved"]') - .parent() - .find('.MuiButtonBase-root') - .click(); - cy.wait(200); - cy.get('button').contains('1').click(); - - cy.get('[id="root_descriptionOfChanges"]').type('test'); - - cy.get('[id="root_levelOfAmendment-0"]').parent().click({ force: true }); - - cy.get('[id="root_additionalComments"]').type('test'); - - cy.get('body').happoScreenshot({ component: 'Change request form' }); - - // Change request excel upload - cy.get('[id="root_statementOfWorkUpload-btn"]').click(); - cy.get('[data-testid=file-test]') - .eq(1) - .selectFile('cypress/fixtures/mock_excel.xlsx', { - force: true, - }); - cy.wait('@sow-upload-validate', { timeout: 50000 }); - cy.contains('button', 'mock_excel.xlsx'); - - // Save change request - cy.contains('Save & Import Data').click(); - - // Community progress report - // Check if accordion is open and open if not due to accordion opening based on dates - cy.get('button') - .contains('Add community progress report') - .then(($button) => { - if ($button.is(':hidden')) { - cy.wait(500); - cy.get('[data-testid=accordion-icon]').parent().eq(3).click(); - } + cy.get('body').happoScreenshot({ + component: `Announcements form - ${role}`, + }); + + // Save announcement + cy.get('#announcements-save-button').click(); + + // Add secondary announcement + cy.get('button').contains('Add announcement').click(); + + cy.get('select[id="root_announcementType"]').select('Secondary'); + + cy.get('[id="root_announcementUrl"]').type('www.e2e-testing.com'); + + cy.get('[id="root_announcementDate"]') + .parent() + .find('.MuiButtonBase-root') + .click(); + cy.wait(200); + cy.get('button').contains('1').click(); + + // Save announcement + cy.get('#announcements-save-button').click(); + + cy.wait('@graphql'); + + // SoW/Change request form + cy.contains('h2', 'Funding agreement, statement of work, & map'); + + cy.get('[id="root_hasFundingAgreementBeenSigned-0"]') + .parent() + .click({ force: true }); + + cy.get('[id="root_dateFundingAgreementSigned"]') + .parent() + .find('.MuiButtonBase-root') + .click(); + cy.wait(200); + cy.get('button').contains('1').click(); + + // Funding agreement upload + cy.get('[id="root_fundingAgreementUpload-btn"]').click(); + cy.get('[data-testid=file-test]') + .first() + .selectFile('cypress/fixtures/doc.txt', { force: true }); + cy.wait(2000); + cy.contains('button', 'doc.txt'); + + // Statement of work excel import + + cy.get('[id="root_statementOfWorkUpload-btn"]').click(); + cy.get('[data-testid=file-test]') + .eq(1) + .selectFile('cypress/fixtures/mock_excel.xlsx', { + force: true, + }); + cy.wait('@sow-upload-validate', { timeout: 50000 }); + cy.contains('button', 'mock_excel.xlsx'); + + cy.get('body').happoScreenshot({ + component: `Statement of work form - ${role}`, + }); + + // Save statement of work + cy.contains('Save & Import Data').click(); + + cy.wait(2000); + + // Add change request + + // Open accordion + cy.get('[data-testid=accordion-icon]').eq(2).parent().click(); + + cy.get('button').contains('Add change request').click(); + + cy.get('[id="root_amendmentNumber"]').type(1); + + cy.get('[id="root_dateRequested"]') + .parent() + .find('.MuiButtonBase-root') + .click(); + cy.wait(200); + cy.get('button').contains('1').click(); + + cy.get('[id="root_dateApproved"]') + .parent() + .find('.MuiButtonBase-root') + .click(); + cy.wait(200); + cy.get('button').contains('1').click(); + + cy.get('[id="root_descriptionOfChanges"]').type('test'); + + cy.get('[id="root_levelOfAmendment-0"]') + .parent() + .click({ force: true }); + + cy.get('[id="root_additionalComments"]').type('test'); + + cy.get('body').happoScreenshot({ + component: `Change request form - ${role}`, + }); + + // Change request excel upload + cy.get('[id="root_statementOfWorkUpload-btn"]').click(); + cy.get('[data-testid=file-test]') + .eq(1) + .selectFile('cypress/fixtures/mock_excel.xlsx', { + force: true, + }); + cy.wait('@sow-upload-validate', { timeout: 50000 }); + cy.contains('button', 'mock_excel.xlsx'); + + // Save change request + cy.contains('Save & Import Data').click(); + + // Community progress report + // Check if accordion is open and open if not due to accordion opening based on dates + cy.get('button') + .contains('Add community progress report') + .then(($button) => { + if ($button.is(':hidden')) { + cy.wait(500); + cy.get('[data-testid=accordion-icon]').parent().eq(3).click(); + } + }); + cy.get('button').contains('Add community progress report').click(); + + cy.contains('h2', 'Community progress report'); + + cy.get('[id="root_dueDate"]') + .first() + .parent() + .find('.MuiButtonBase-root') + .click(); + cy.wait(200); + cy.get('button').contains('1').click(); + + cy.wait(1000); + + cy.get('[id="root_dateReceived"]') + .parent() + .find('.MuiButtonBase-root') + .click(); + cy.wait(200); + cy.get('button').contains('1').click(); + + // Community progress report excel upload + cy.get('[id="root_progressReportFile-btn"]').click(); + cy.get('[data-testid=file-test]') + .first() + .selectFile('cypress/fixtures/mock_excel.xlsx', { + force: true, + }); + cy.wait('@community-report-validate', { timeout: 50000 }); + cy.contains('button', 'mock_excel.xlsx'); + cy.get('body').happoScreenshot({ + component: `Community progress form - ${role}`, + }); + + cy.contains('Save & Import').click(); + + // Milestones + // Check if accordion is open and open if not due to accordion opening based on dates + cy.get('button') + .contains('Add milestone report') + .then(($button) => { + if ($button.is(':hidden')) { + cy.wait(500); + cy.get('[data-testid=accordion-icon]').parent().eq(4).click(); + } + }); + + cy.wait(500); + cy.get('button').contains('Add milestone report').click(); + + cy.get('[id="root_dueDate"]') + .first() + .parent() + .find('.MuiButtonBase-root') + .click(); + cy.wait(200); + cy.get('button').contains('1').click(); + + // Milestone excel upload + cy.get('[id="root_milestoneFile-btn"]').click(); + cy.get('[data-testid=file-test]') + .first() + .selectFile('cypress/fixtures/mock_excel.xlsx', { + force: true, + }); + cy.wait('@milestone-validate', { timeout: 50000 }); + + cy.get('[id="root_evidenceOfCompletionFile-btn"]').click(); + cy.get('[data-testid=file-test]') + .eq(1) + .selectFile('cypress/fixtures/mock_excel.xlsx', { + force: true, + }); + + cy.contains('button', 'mock_excel.xlsx'); + cy.get('body').happoScreenshot({ + component: `Milestones form - ${role}`, + }); + + // Save milestone + cy.get('button').contains('Save & Import').click(); + + // Claims + // Check if accordion is open and open if not due to accordion opening based on dates + cy.get('button') + .contains('Add claim') + .then(($button) => { + if ($button.is(':hidden')) { + cy.wait(500); + cy.get('[data-testid=accordion-icon]').parent().eq(5).click(); + } + }); + + cy.wait(500); + cy.get('button').contains('Add claim').click(); + + // Claim excel upload + cy.get('[id="root_claimsFile-btn"]').click(); + cy.get('[data-testid=file-test]') + .first() + .selectFile('cypress/fixtures/mock_excel.xlsx', { + force: true, + }); + cy.wait('@claims-validate', { timeout: 50000 }); + cy.contains('button', 'mock_excel.xlsx'); + cy.get('body').happoScreenshot({ component: `Claims form - ${role}` }); + + // Save claim + cy.get('button').contains('Save & Import').click(); + + cy.get('body').happoScreenshot({ + component: `Project page all forms complete - ${role}`, + }); }); - cy.get('button').contains('Add community progress report').click(); - - cy.contains('h2', 'Community progress report'); - - cy.get('[id="root_dueDate"]') - .first() - .parent() - .find('.MuiButtonBase-root') - .click(); - cy.wait(200); - cy.get('button').contains('1').click(); - - cy.wait(1000); - - cy.get('[id="root_dateReceived"]') - .parent() - .find('.MuiButtonBase-root') - .click(); - cy.wait(200); - cy.get('button').contains('1').click(); - - // Community progress report excel upload - cy.get('[id="root_progressReportFile-btn"]').click(); - cy.get('[data-testid=file-test]') - .first() - .selectFile('cypress/fixtures/mock_excel.xlsx', { - force: true, - }); - cy.wait('@community-report-validate', { timeout: 50000 }); - cy.contains('button', 'mock_excel.xlsx'); - cy.get('body').happoScreenshot({ component: 'Community progress form' }); - - cy.contains('Save & Import').click(); - - // Milestones - // Check if accordion is open and open if not due to accordion opening based on dates - cy.get('button') - .contains('Add milestone report') - .then(($button) => { - if ($button.is(':hidden')) { - cy.wait(500); - cy.get('[data-testid=accordion-icon]').parent().eq(4).click(); - } - }); - - cy.wait(500); - cy.get('button').contains('Add milestone report').click(); - - cy.get('[id="root_dueDate"]') - .first() - .parent() - .find('.MuiButtonBase-root') - .click(); - cy.wait(200); - cy.get('button').contains('1').click(); - - // Milestone excel upload - cy.get('[id="root_milestoneFile-btn"]').click(); - cy.get('[data-testid=file-test]') - .first() - .selectFile('cypress/fixtures/mock_excel.xlsx', { - force: true, - }); - cy.wait('@milestone-validate', { timeout: 50000 }); - - cy.get('[id="root_evidenceOfCompletionFile-btn"]').click(); - cy.get('[data-testid=file-test]') - .eq(1) - .selectFile('cypress/fixtures/mock_excel.xlsx', { - force: true, - }); - - cy.contains('button', 'mock_excel.xlsx'); - cy.get('body').happoScreenshot({ component: 'Milestones form' }); - - // Save milestone - cy.get('button').contains('Save & Import').click(); - - // Claims - // Check if accordion is open and open if not due to accordion opening based on dates - cy.get('button') - .contains('Add claim') - .then(($button) => { - if ($button.is(':hidden')) { - cy.wait(500); - cy.get('[data-testid=accordion-icon]').parent().eq(5).click(); - } - }); - - cy.wait(500); - cy.get('button').contains('Add claim').click(); - - // Claim excel upload - cy.get('[id="root_claimsFile-btn"]').click(); - cy.get('[data-testid=file-test]') - .first() - .selectFile('cypress/fixtures/mock_excel.xlsx', { - force: true, - }); - cy.wait('@claims-validate', { timeout: 50000 }); - cy.contains('button', 'mock_excel.xlsx'); - cy.get('body').happoScreenshot({ component: 'Claims form' }); - - // Save claim - cy.get('button').contains('Save & Import').click(); - - cy.get('body').happoScreenshot({ - component: 'Project page all forms complete', }); }); }); diff --git a/app/cypress/e2e/analyst/application/[applicationId]/rfi/index.cy.js b/app/cypress/e2e/analyst/application/[applicationId]/rfi/index.cy.js index b94f61d6a8..1c3d58e1ed 100644 --- a/app/cypress/e2e/analyst/application/[applicationId]/rfi/index.cy.js +++ b/app/cypress/e2e/analyst/application/[applicationId]/rfi/index.cy.js @@ -1,41 +1,57 @@ /* eslint-disable import/extensions */ -import rfiSetup from './setup.cy.js'; +import { + rfiSetup, + rfiSetupCcbcAdmin, + rfiSetupCbcAdmin, + rfiSetupSuperAdmin, +} from './setup.cy.js'; + +const setups = [ + { setup: rfiSetup, role: 'Default Analyst' }, + { setup: rfiSetupCcbcAdmin, role: 'CCBC Admin' }, + { setup: rfiSetupCbcAdmin, role: 'CBC Admin' }, + { setup: rfiSetupSuperAdmin, role: 'Super Admin' }, +]; describe('The RFI index page', () => { - beforeEach(() => { - rfiSetup(); - }); + setups.forEach(({ setup, role }) => { + describe(`as ${role}`, () => { + beforeEach(() => { + setup(); + }); - it('loads', () => { - cy.visit('/analyst/application/1/rfi'); - cy.contains('h2', 'RFI'); - cy.get('body').happoScreenshot({ - component: 'Empty Rfi Page', - }); - }); + it('loads', () => { + cy.visit('/analyst/application/1/rfi'); + cy.contains('h2', 'RFI'); + cy.get('body').happoScreenshot({ + component: `Empty Rfi Page - ${role}`, + }); + }); - it('Create new RFI', () => { - cy.visit('/analyst/application/1/rfi'); - cy.contains('h2', 'RFI'); - cy.wait('@graphql'); - cy.contains('button', 'New RFI').click(); - cy.url().should('contain', '/analyst/application/1/rfi/0'); - cy.get('[data-testid=file-test]') - .first() - .selectFile('cypress/fixtures/doc.txt', { force: true }); - cy.get('input[id="root_rfiAdditionalFiles_detailedBudgetRfi"]') - .parent() - .click(); - cy.get('input[id="root_rfiType-0"]').parent().click(); - cy.contains('button', /^Save$/).click(); - cy.get('svg[data-icon="pen"]').should('exist'); - cy.get('body').happoScreenshot({ - component: 'Saved Rfi Index Page', - }); - cy.get('svg[data-icon="pen"]').click(); - cy.get('[data-testid=file-test]').should('exist'); - cy.get('body').happoScreenshot({ - component: 'Saved Rfi Page', + it('Creates a new RFI', () => { + cy.visit('/analyst/application/1/rfi'); + cy.contains('h2', 'RFI'); + cy.wait('@graphql'); + cy.contains('button', 'New RFI').click(); + cy.url().should('contain', '/analyst/application/1/rfi/0'); + cy.get('[data-testid=file-test]') + .first() + .selectFile('cypress/fixtures/doc.txt', { force: true }); + cy.get('input[id="root_rfiAdditionalFiles_detailedBudgetRfi"]') + .parent() + .click(); + cy.get('input[id="root_rfiType-0"]').parent().click(); + cy.contains('button', /^Save$/).click(); + cy.get('svg[data-icon="pen"]').should('exist'); + cy.get('body').happoScreenshot({ + component: `Saved RFI Index Page - ${role}`, + }); + cy.get('svg[data-icon="pen"]').click(); + cy.get('[data-testid=file-test]').should('exist'); + cy.get('body').happoScreenshot({ + component: `Saved RFI Page - ${role}`, + }); + }); }); }); }); diff --git a/app/cypress/e2e/analyst/application/[applicationId]/rfi/setup.cy.js b/app/cypress/e2e/analyst/application/[applicationId]/rfi/setup.cy.js index f4baafddab..a22bc5665d 100644 --- a/app/cypress/e2e/analyst/application/[applicationId]/rfi/setup.cy.js +++ b/app/cypress/e2e/analyst/application/[applicationId]/rfi/setup.cy.js @@ -11,4 +11,43 @@ const rfiSetup = () => { cy.intercept('POST', '/graphql').as('graphql'); }; -export default rfiSetup; +const rfiSetupCcbcAdmin = () => { + cy.mockLogin('ccbc_admin'); + const mockedDateString = '2022-10-10'; + const mockedDate = new Date(mockedDateString); + cy.useMockedTime(mockedDate); + cy.sqlFixture('e2e/reset_db'); + cy.sqlFixture('e2e/001_intake'); + cy.sqlFixture('e2e/001_application'); + cy.sqlFixture('e2e/001_application_received'); + cy.sqlFixture('e2e/001_analyst'); + cy.intercept('POST', '/graphql').as('graphql'); +}; + +const rfiSetupCbcAdmin = () => { + cy.mockLogin('cbc_admin'); + const mockedDateString = '2022-10-10'; + const mockedDate = new Date(mockedDateString); + cy.useMockedTime(mockedDate); + cy.sqlFixture('e2e/reset_db'); + cy.sqlFixture('e2e/001_intake'); + cy.sqlFixture('e2e/001_application'); + cy.sqlFixture('e2e/001_application_received'); + cy.sqlFixture('e2e/001_analyst'); + cy.intercept('POST', '/graphql').as('graphql'); +}; + +const rfiSetupSuperAdmin = () => { + cy.mockLogin('super_admin'); + const mockedDateString = '2022-10-10'; + const mockedDate = new Date(mockedDateString); + cy.useMockedTime(mockedDate); + cy.sqlFixture('e2e/reset_db'); + cy.sqlFixture('e2e/001_intake'); + cy.sqlFixture('e2e/001_application'); + cy.sqlFixture('e2e/001_application_received'); + cy.sqlFixture('e2e/001_analyst'); + cy.intercept('POST', '/graphql').as('graphql'); +}; + +export { rfiSetupCcbcAdmin, rfiSetupCbcAdmin, rfiSetupSuperAdmin, rfiSetup }; diff --git a/app/cypress/e2e/analyst/cbc/[cbcId].cy.js b/app/cypress/e2e/analyst/cbc/[cbcId].cy.js index 671acc21af..941a2f002a 100644 --- a/app/cypress/e2e/analyst/cbc/[cbcId].cy.js +++ b/app/cypress/e2e/analyst/cbc/[cbcId].cy.js @@ -1,3 +1,16 @@ +const loadTest = (role) => { + cy.visit('/analyst/cbc/1'); + cy.contains('h1', 'Project 1'); + cy.contains('h2', 'Tombstone'); + cy.contains('h2', 'Project type'); + cy.contains('h2', 'Locations'); + cy.contains('h2', 'Counts'); + cy.contains('h2', 'Funding'); + cy.contains('h2', 'Events and dates'); + cy.contains('h2', 'Miscellaneous'); + cy.contains('h2', 'Project data reviews'); + cy.get('body').happoScreenshot({ component: `CBC project view - ${role}` }); +}; describe('The cbc project view', () => { beforeEach(() => { cy.mockLogin('cbc_admin'); @@ -10,26 +23,29 @@ describe('The cbc project view', () => { cy.sqlFixture('e2e/001_application_received'); cy.sqlFixture('e2e/001_analyst'); }); + describe('cbc load tests for each role', () => { + const roles = ['ccbc_analyst', 'ccbc_admin', 'super_admin', 'cbc_admin']; + roles.forEach((role) => { + it(`loads for ${role}`, () => { + loadTest(role); + }); + }); + }); - it('loads', () => { + it('triggers quick edit cbc_admin', () => { cy.visit('/analyst/cbc/1'); - cy.contains('h1', 'Project 1'); - cy.contains('h2', 'Tombstone'); - cy.contains('h2', 'Project type'); - cy.contains('h2', 'Locations'); - cy.contains('h2', 'Counts'); - cy.contains('h2', 'Funding'); - cy.contains('h2', 'Events and dates'); - cy.contains('h2', 'Miscellaneous'); - cy.contains('h2', 'Project data reviews'); - cy.get('body').happoScreenshot({ component: 'CBC project view' }); + cy.get('button').contains('Quick edit').click(); + cy.get('body').happoScreenshot({ + component: 'CBC project view - quick edit cbc_admin', + }); }); - it('triggers quick edit', () => { + it('triggers quick edit cbc_admin', () => { + cy.mockLogin('super_admin'); cy.visit('/analyst/cbc/1'); cy.get('button').contains('Quick edit').click(); cy.get('body').happoScreenshot({ - component: 'CBC project view - quick edit', + component: 'CBC project view - quick edit super_admin', }); }); }); diff --git a/app/cypress/e2e/analyst/dashboard.cy.js b/app/cypress/e2e/analyst/dashboard.cy.js index b509e6d74a..66c19bf64e 100644 --- a/app/cypress/e2e/analyst/dashboard.cy.js +++ b/app/cypress/e2e/analyst/dashboard.cy.js @@ -1,44 +1,76 @@ -describe('The analyst dashboard', () => { - // eslint-disable-next-line prefer-arrow-callback, func-names - beforeEach(function () { - const mockedDateString = '2022-10-10'; - const mockedDate = new Date(mockedDateString); - cy.useMockedTime(mockedDate); - cy.sqlFixture('e2e/reset_db_all'); - cy.sqlFixture('e2e/001_intake'); - cy.sqlFixture('e2e/001_received_applications'); - cy.sqlFixture('e2e/001_cbc_project'); - cy.sqlFixture('e2e/001_analyst'); - cy.mockLogin('ccbc_analyst'); - }); +describe('The Analyst Dashboard', () => { + // Define the roles to be tested + const roles = ['cbc_admin', 'ccbc_analyst', 'ccbc_admin', 'super_admin']; - it('loads', () => { - cy.visit('/analyst/dashboard'); - cy.contains('a', 'Dashboard'); - cy.get('body').happoScreenshot({ component: 'Analyst Dashboard' }); - }); + // Iterate through each role + roles.forEach((role) => { + describe(`As ${role}`, () => { + // Setup before each test for the current role + beforeEach(() => { + const mockedDateString = '2022-10-10'; + const mockedDate = new Date(mockedDateString); - it('click on dashboard row', () => { - cy.visit('/analyst/dashboard'); - // need to add to prevent "is detached from the dom" issue - cy.wait(2000); - cy.contains('a', 'CCBC-010001').click(); - cy.url().should('include', '/analyst/application/'); - }); + // Mock the current time + cy.useMockedTime(mockedDate); + + // Load necessary SQL fixtures + cy.sqlFixture('e2e/reset_db_all'); + cy.sqlFixture('e2e/001_intake'); + cy.sqlFixture('e2e/001_received_applications'); + cy.sqlFixture('e2e/001_cbc_project'); + cy.sqlFixture('e2e/001_analyst'); + + // Mock login for the current role + cy.mockLogin(role); + }); + + it('loads the dashboard', () => { + cy.visit('/analyst/dashboard'); + cy.contains('a', 'Dashboard'); + + // Capture a Happo screenshot with the role specified + cy.get('body').happoScreenshot({ + component: `Analyst Dashboard - ${role}`, + }); + }); + + it('clicks on a dashboard row', () => { + cy.visit('/analyst/dashboard'); + + // Wait to ensure elements are loaded and prevent "detached from DOM" issues + cy.wait(2000); + + // Click on a specific dashboard row + cy.contains('a', 'CCBC-010001').click(); + + // Verify the URL after clicking + cy.url().should('include', '/analyst/application/'); + }); + + it('sorts the dashboard', () => { + cy.visit('/analyst/dashboard'); + + // Wait to ensure elements are loaded + cy.wait(2000); + + // Click on the second table header to sort + cy.get('tr > th').eq(1).click(); - it('sort dashboard', () => { - cy.visit('/analyst/dashboard'); - cy.wait(2000); - cy.get('tr > th').eq(1).click(); - cy.getCookie('mrt_sorting_application').should( - 'have.property', - 'value', - '[{%22id%22:%22intakeNumber%22%2C%22desc%22:true}]' - ); + // Verify that the sorting cookie is set correctly + cy.getCookie('mrt_sorting_application').should( + 'have.property', + 'value', + '[{%22id%22:%22intakeNumber%22%2C%22desc%22:true}]' + ); - // add wait to prevent happo diff from taking a screenshot before the sort is complete - cy.wait(2000); + // Wait to ensure sorting is complete before taking the screenshot + cy.wait(2000); - cy.get('body').happoScreenshot({ component: 'Sorted Analyst Dashboard' }); + // Capture a Happo screenshot with the role specified + cy.get('body').happoScreenshot({ + component: `Sorted Analyst Dashboard - ${role}`, + }); + }); + }); }); }); From 598d548d6f39778dc561dfcd1dd7ff2d2edf72b8 Mon Sep 17 00:00:00 2001 From: CCBC Service Account <116113628+ccbc-service-account@users.noreply.github.com> Date: Fri, 29 Nov 2024 19:45:43 +0000 Subject: [PATCH 07/21] chore: release v1.213.2 --- CHANGELOG.md | 2 ++ db/sqitch.plan | 1 + package.json | 2 +- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e0214fa826..a55419e263 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ +## [1.213.2](https://github.com/bcgov/CONN-CCBC-portal/compare/v1.213.1...v1.213.2) (2024-11-29) + ## [1.213.1](https://github.com/bcgov/CONN-CCBC-portal/compare/v1.213.0...v1.213.1) (2024-11-29) ### Bug Fixes diff --git a/db/sqitch.plan b/db/sqitch.plan index 74ae9de9fa..b68b1816d8 100644 --- a/db/sqitch.plan +++ b/db/sqitch.plan @@ -749,3 +749,4 @@ computed_columns/application_history [computed_columns/application_history@1.204 mutations/create_assessment_form [mutations/create_assessment_form@1.204.0] 2024-11-12T23:02:06Z Rafael Solorzano <61289255+rafasdc@users.noreply.github.com> # add case for application dependencies @1.213.0 2024-11-27T00:06:15Z CCBC Service Account # release v1.213.0 @1.213.1 2024-11-29T17:06:22Z CCBC Service Account # release v1.213.1 +@1.213.2 2024-11-29T19:45:41Z CCBC Service Account # release v1.213.2 diff --git a/package.json b/package.json index c2949e90c2..a86a423543 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "CONN-CCBC-portal", - "version": "1.213.1", + "version": "1.213.2", "main": "index.js", "repository": "https://github.com/bcgov/CONN-CCBC-portal.git", "author": "Romer, Meherzad CITZ:EX ", From d7d29a0c72331dc2ebcea90528a3ebb55af733a6 Mon Sep 17 00:00:00 2001 From: Rafael Solorzano <61289255+rafasdc@users.noreply.github.com> Date: Wed, 27 Nov 2024 14:00:50 -0800 Subject: [PATCH 08/21] fix: deterministic session secret --- .github/actions/app/action.yaml | 4 ++++ .github/workflows/deploy.yaml | 4 ++++ .github/workflows/main.yaml | 1 + helm/app/templates/secret.yaml | 2 +- helm/app/values.yaml | 1 + 5 files changed, 11 insertions(+), 1 deletion(-) diff --git a/.github/actions/app/action.yaml b/.github/actions/app/action.yaml index d2365bea30..b6c05dadd0 100644 --- a/.github/actions/app/action.yaml +++ b/.github/actions/app/action.yaml @@ -118,6 +118,9 @@ inputs: coverages_file: description: 'Coverages file' required: true + session_secret: + description: 'Session secret' + required: true runs: using: composite @@ -191,6 +194,7 @@ runs: --set cronshp.erFile="${{ inputs.er_file }}" \ --set cronshp.rdFile="${{ inputs.rd_file }}" \ --set cronshp.coveragesFile="${{ inputs.coverages_file }}" \ + --set app.sessionSecret="${ inputs.session_secret }}" \ --values values-${{ inputs.environment }}.yaml shell: bash diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml index 06b4e9b3c4..61ddcd3f8d 100644 --- a/.github/workflows/deploy.yaml +++ b/.github/workflows/deploy.yaml @@ -47,6 +47,7 @@ on: ER_FILE: { required: true } RD_FILE: { required: true } COVERAGES_FILE: { required: true } + SESSION_SECRET: { required: true } env: TAG: sha-${{ github.sha }} @@ -120,6 +121,7 @@ jobs: er_file: ${{ secrets.ER_FILE }} rd_file: ${{ secrets.RD_FILE }} coverages_file: ${{ secrets.COVERAGES_FILE }} + session_secret: ${{ secrets.SESSION_SECRET }} environment: dev ensure-sqitch-plan-ends-with-tag: @@ -188,6 +190,7 @@ jobs: er_file: ${{ secrets.ER_FILE }} rd_file: ${{ secrets.RD_FILE }} coverages_file: ${{ secrets.COVERAGES_FILE }} + session_secret: ${{ secrets.SESSION_SECRET }} environment: test deploy-to-openshift-production: @@ -247,6 +250,7 @@ jobs: er_file: ${{ secrets.ER_FILE }} rd_file: ${{ secrets.RD_FILE }} coverages_file: ${{ secrets.COVERAGES_FILE }} + session_secret: ${{ secrets.SESSION_SECRET }} environment: prod backup-secrets-dev: diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 063c3371e5..09d94ad417 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -212,6 +212,7 @@ jobs: ER_FILE: ${{ secrets.ER_FILE }} RD_FILE: ${{ secrets.RD_FILE }} COVERAGES_FILE: ${{ secrets.COVERAGES_FILE }} + SESSION_SECRET: ${{ secrets.SESSION_SECRET }} deploy-feature: if: github.event_name == 'pull_request' && github.event.pull_request.draft == false diff --git a/helm/app/templates/secret.yaml b/helm/app/templates/secret.yaml index b39891e07a..4ed4d084bc 100644 --- a/helm/app/templates/secret.yaml +++ b/helm/app/templates/secret.yaml @@ -21,7 +21,7 @@ metadata: "helm.sh/hook": "pre-install,pre-upgrade" type: Opaque data: - session-secret: {{ randAlphaNum 32 | b64enc | quote }} + session-secret: {{ .Values.app.sessionSecret | b64enc | quote }} database-name: {{ .Values.db.name | b64enc | quote }} database-app-user: {{ .Values.db.appUser | b64enc | quote }} database-app-password: {{ $dbAppPassword }} diff --git a/helm/app/values.yaml b/helm/app/values.yaml index 6c265506c5..e9e88e9858 100644 --- a/helm/app/values.yaml +++ b/helm/app/values.yaml @@ -59,6 +59,7 @@ app: probesPort: '9000' namespace: '' enableAnalytics: true + sessionSecret: '' # sessionSecret must be passed in via deploy script secureRoute: host: '' # The host value must be passed in via the deploy script wwwRoute: From f0a5756060a4f5658f7511fce6e4a618525f05a3 Mon Sep 17 00:00:00 2001 From: CCBC Service Account <116113628+ccbc-service-account@users.noreply.github.com> Date: Fri, 29 Nov 2024 22:33:03 +0000 Subject: [PATCH 09/21] chore: release v1.213.3 --- CHANGELOG.md | 6 ++++++ db/sqitch.plan | 1 + package.json | 2 +- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a55419e263..4ea8a46d43 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [1.213.3](https://github.com/bcgov/CONN-CCBC-portal/compare/v1.213.2...v1.213.3) (2024-11-29) + +### Bug Fixes + +- deterministic session secret ([d7d29a0](https://github.com/bcgov/CONN-CCBC-portal/commit/d7d29a0c72331dc2ebcea90528a3ebb55af733a6)) + ## [1.213.2](https://github.com/bcgov/CONN-CCBC-portal/compare/v1.213.1...v1.213.2) (2024-11-29) ## [1.213.1](https://github.com/bcgov/CONN-CCBC-portal/compare/v1.213.0...v1.213.1) (2024-11-29) diff --git a/db/sqitch.plan b/db/sqitch.plan index b68b1816d8..79fe5b34c5 100644 --- a/db/sqitch.plan +++ b/db/sqitch.plan @@ -750,3 +750,4 @@ mutations/create_assessment_form [mutations/create_assessment_form@1.204.0] 2024 @1.213.0 2024-11-27T00:06:15Z CCBC Service Account # release v1.213.0 @1.213.1 2024-11-29T17:06:22Z CCBC Service Account # release v1.213.1 @1.213.2 2024-11-29T19:45:41Z CCBC Service Account # release v1.213.2 +@1.213.3 2024-11-29T22:33:02Z CCBC Service Account # release v1.213.3 diff --git a/package.json b/package.json index a86a423543..b61f7ea74c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "CONN-CCBC-portal", - "version": "1.213.2", + "version": "1.213.3", "main": "index.js", "repository": "https://github.com/bcgov/CONN-CCBC-portal.git", "author": "Romer, Meherzad CITZ:EX ", From fb2485afc8327e9d5cf1bcac47c95f9f4591e68b Mon Sep 17 00:00:00 2001 From: Rafael Solorzano <61289255+rafasdc@users.noreply.github.com> Date: Mon, 2 Dec 2024 09:44:31 -0800 Subject: [PATCH 10/21] chore: set proper session secret --- .github/actions/app/action.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/actions/app/action.yaml b/.github/actions/app/action.yaml index b6c05dadd0..0e2fdb1419 100644 --- a/.github/actions/app/action.yaml +++ b/.github/actions/app/action.yaml @@ -146,6 +146,7 @@ runs: cert_key: ${{ inputs.cert_key }} cert_ca: ${{ inputs.cert_ca }} pgbackrest_s3_bucket: ${{ inputs.pgbackrest_s3_bucket }} + session_secret: ${{ inputs.session_secret }} insecure_skip_tls_verify: true - run: | SHA_ONLY=$(echo ${{ inputs.tag }} | cut -c 5-) From 2113652556c3219ad0b5e784c4b7f1156f9fee4d Mon Sep 17 00:00:00 2001 From: Rafael Solorzano <61289255+rafasdc@users.noreply.github.com> Date: Mon, 2 Dec 2024 09:45:27 -0800 Subject: [PATCH 11/21] chore: temp enable deploy --- .github/workflows/main.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 09d94ad417..8e4eaa3037 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -164,8 +164,8 @@ jobs: - run: ./.bin/sqitch-last-change-is-tag.sh db deploy: - if: github.event.ref == 'refs/heads/main' - needs: [test-code, test-containers] + # if: github.event.ref == 'refs/heads/main' + needs: [build] uses: ./.github/workflows/deploy.yaml secrets: OPENSHIFT_SERVER: ${{ secrets.OPENSHIFT_SERVER }} From 4a0fe4141c2e74bf4b6f85e547aef3fbba81bb11 Mon Sep 17 00:00:00 2001 From: Rafael Solorzano <61289255+rafasdc@users.noreply.github.com> Date: Mon, 2 Dec 2024 09:59:46 -0800 Subject: [PATCH 12/21] chore: correct substitution --- .github/actions/app/action.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/app/action.yaml b/.github/actions/app/action.yaml index 0e2fdb1419..6f9454c4d9 100644 --- a/.github/actions/app/action.yaml +++ b/.github/actions/app/action.yaml @@ -195,7 +195,7 @@ runs: --set cronshp.erFile="${{ inputs.er_file }}" \ --set cronshp.rdFile="${{ inputs.rd_file }}" \ --set cronshp.coveragesFile="${{ inputs.coverages_file }}" \ - --set app.sessionSecret="${ inputs.session_secret }}" \ + --set app.sessionSecret="${{ inputs.session_secret }}" \ --values values-${{ inputs.environment }}.yaml shell: bash From fdcf7c85bb96deb2b408696e1cf97b293a4efb56 Mon Sep 17 00:00:00 2001 From: Rafael Solorzano <61289255+rafasdc@users.noreply.github.com> Date: Mon, 2 Dec 2024 10:40:37 -0800 Subject: [PATCH 13/21] chore: revert temp change --- .github/workflows/main.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 8e4eaa3037..09d94ad417 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -164,8 +164,8 @@ jobs: - run: ./.bin/sqitch-last-change-is-tag.sh db deploy: - # if: github.event.ref == 'refs/heads/main' - needs: [build] + if: github.event.ref == 'refs/heads/main' + needs: [test-code, test-containers] uses: ./.github/workflows/deploy.yaml secrets: OPENSHIFT_SERVER: ${{ secrets.OPENSHIFT_SERVER }} From d93719d3b5254d1c094d477f5d0f956c024d3cdf Mon Sep 17 00:00:00 2001 From: CCBC Service Account <116113628+ccbc-service-account@users.noreply.github.com> Date: Tue, 3 Dec 2024 16:39:31 +0000 Subject: [PATCH 14/21] chore: release v1.213.4 --- CHANGELOG.md | 2 ++ db/sqitch.plan | 1 + package.json | 2 +- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ea8a46d43..ecf41fce8e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ +## [1.213.4](https://github.com/bcgov/CONN-CCBC-portal/compare/v1.213.3...v1.213.4) (2024-12-03) + ## [1.213.3](https://github.com/bcgov/CONN-CCBC-portal/compare/v1.213.2...v1.213.3) (2024-11-29) ### Bug Fixes diff --git a/db/sqitch.plan b/db/sqitch.plan index 79fe5b34c5..6320927876 100644 --- a/db/sqitch.plan +++ b/db/sqitch.plan @@ -751,3 +751,4 @@ mutations/create_assessment_form [mutations/create_assessment_form@1.204.0] 2024 @1.213.1 2024-11-29T17:06:22Z CCBC Service Account # release v1.213.1 @1.213.2 2024-11-29T19:45:41Z CCBC Service Account # release v1.213.2 @1.213.3 2024-11-29T22:33:02Z CCBC Service Account # release v1.213.3 +@1.213.4 2024-12-03T16:39:29Z CCBC Service Account # release v1.213.4 diff --git a/package.json b/package.json index b61f7ea74c..2ec24912dc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "CONN-CCBC-portal", - "version": "1.213.3", + "version": "1.213.4", "main": "index.js", "repository": "https://github.com/bcgov/CONN-CCBC-portal.git", "author": "Romer, Meherzad CITZ:EX ", From ef8f11ddb95b1c74ca396bff181577d30732b93e Mon Sep 17 00:00:00 2001 From: R Ranathunga Date: Wed, 20 Nov 2024 07:57:25 -0800 Subject: [PATCH 15/21] feat: enable global filter to filter communities --- .../AnalystDashboard/AllDashboard.tsx | 36 +++++++++++- .../AllDashboardDetailPanel.tsx | 37 +++++++++++- app/components/Table/ClearFilters.tsx | 9 ++- app/tests/pages/analyst/dashboard.test.tsx | 56 +++++++++++++++++++ 4 files changed, 133 insertions(+), 5 deletions(-) diff --git a/app/components/AnalystDashboard/AllDashboard.tsx b/app/components/AnalystDashboard/AllDashboard.tsx index 88c3787171..bf91ac98f9 100644 --- a/app/components/AnalystDashboard/AllDashboard.tsx +++ b/app/components/AnalystDashboard/AllDashboard.tsx @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/no-shadow */ /* eslint-disable react/jsx-pascal-case */ -import { useCallback, useEffect, useMemo, useState } from 'react'; +import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { graphql, useFragment } from 'react-relay'; import styled from 'styled-components'; import cookie from 'js-cookie'; @@ -18,6 +18,7 @@ import { MRT_ToggleDensePaddingButton, MRT_ToggleFullScreenButton, MRT_ShowHideColumnsButton, + MRT_FilterFns, } from 'material-react-table'; import RowCount from 'components/Table/RowCount'; @@ -302,6 +303,10 @@ const AllDashboardTable: React.FC = ({ query }) => { const [showColumnFilters, setShowColumnFilters] = useState(false); const [sorting, setSorting] = useState([]); + const [expanded, setExpanded] = useState({}); + const [globalFilter, setGlobalFilter] = useState(null); + + const expandedRowsRef = useRef({}); const [columnSizing, setColumnSizing] = useState({ 'mrt-row-expand': 40, @@ -442,6 +447,11 @@ const AllDashboardTable: React.FC = ({ query }) => { } }, [visibilityPreference]); + useEffect(() => { + setExpanded(globalFilter ? expandedRowsRef.current : {}); + expandedRowsRef.current = {}; + }, [globalFilter]); + const state = { showGlobalFilter: true, columnFilters, @@ -450,6 +460,20 @@ const AllDashboardTable: React.FC = ({ query }) => { showColumnFilters, sorting, columnSizing, + expanded, + globalFilter, + }; + + const customGlobalFilter = (row, id, filterValue, filterMeta) => { + const defaultMatch = MRT_FilterFns.fuzzy(row, id, filterValue, filterMeta); + const communitiesString = row.original.communities + ?.map((item) => item.geoName) + .join(',') + ?.toLowerCase(); + const detailsMatch = communitiesString?.includes(filterValue.toLowerCase()); + expandedRowsRef.current[row.id] = detailsMatch; + + return defaultMatch || detailsMatch; }; const getCommunities = (application) => { @@ -689,8 +713,16 @@ const AllDashboardTable: React.FC = ({ query }) => { filterFns: { filterNumber, statusFilter, + customGlobalFilter, + }, + renderDetailPanel: ({ row }) => ( + + ), + globalFilterFn: 'customGlobalFilter', + onGlobalFilterChange: setGlobalFilter, + onExpandedChange: (expanded) => { + setExpanded(expanded); }, - renderDetailPanel: ({ row }) => , renderToolbarInternalActions: ({ table }) => ( diff --git a/app/components/AnalystDashboard/AllDashboardDetailPanel.tsx b/app/components/AnalystDashboard/AllDashboardDetailPanel.tsx index 5c4eeb4ed4..cf4552b057 100644 --- a/app/components/AnalystDashboard/AllDashboardDetailPanel.tsx +++ b/app/components/AnalystDashboard/AllDashboardDetailPanel.tsx @@ -2,6 +2,7 @@ import styled from 'styled-components'; interface Props { row: any; + filterValue: string; } const StyledMapLink = styled.a` @@ -17,7 +18,36 @@ const StyledSpan = styled.span` display: block; `; -const AllDashboardDetailPanel: React.FC = ({ row }) => { +const StyledHighlightSpan = styled.span` + background-color: ${(props) => props.theme.color.primaryYellow}; +`; + +const HighlightFilterMatch = ({ text, filterValue }) => { + if (!filterValue) return text; + + const normalizedFilterValue = filterValue.replace(/\s+/g, '').toLowerCase(); + const normalizedText = text.replace(/\s+/g, '').toLowerCase(); + + const matchIndex = normalizedText.indexOf(normalizedFilterValue); + + if (matchIndex === -1) { + return text; + } + + const beforeMatch = text.slice(0, matchIndex); + const match = text.slice(matchIndex, matchIndex + filterValue.length); + const afterMatch = text.slice(matchIndex + filterValue.length); + + return ( + <> + {beforeMatch} + {match} + {afterMatch} + + ); +}; + +const AllDashboardDetailPanel: React.FC = ({ row, filterValue }) => { const communities = (row.original.communities as any[]) || []; return ( <> @@ -30,7 +60,10 @@ const AllDashboardDetailPanel: React.FC = ({ row }) => { target="_blank" rel="noopener noreferrer" > - {item.geoName} + {index < communities.length - 1 && ', '} diff --git a/app/components/Table/ClearFilters.tsx b/app/components/Table/ClearFilters.tsx index 34780c31e9..a2f0bc7c58 100644 --- a/app/components/Table/ClearFilters.tsx +++ b/app/components/Table/ClearFilters.tsx @@ -19,6 +19,7 @@ const ClearFilters: React.FC = ({ const clearFilters = () => { table.resetColumnFilters(); table.setColumnFilters(defaultFilters); + table.setGlobalFilter(''); }; const isTableFiltersPresent = @@ -29,9 +30,15 @@ const ClearFilters: React.FC = ({ filters.filter((f) => f.id === 'program' && (f.value as any[]).length < 3) .length > 0; + const isGlobalFilterPresent = table.getState().globalFilter !== ''; + return (