diff --git a/src/altinn-app-frontend/src/components/summary/SummaryComponent.tsx b/src/altinn-app-frontend/src/components/summary/SummaryComponent.tsx index 6e4e35d17d..dc45483be1 100644 --- a/src/altinn-app-frontend/src/components/summary/SummaryComponent.tsx +++ b/src/altinn-app-frontend/src/components/summary/SummaryComponent.tsx @@ -50,7 +50,12 @@ export function SummaryComponent({ id, grid, ...summaryProps }: ISummaryComponen const GetHiddenSelector = makeGetHidden(); const [componentValidations, setComponentValidations] = React.useState({}); const [hasValidationMessages, setHasValidationMessages] = React.useState(false); - const hidden: boolean = useAppSelector((state) => GetHiddenSelector(state, { id })); + const hidden = useAppSelector((state) => { + if (GetHiddenSelector(state, { id })) { + return true; + } + return !!(componentRef && GetHiddenSelector(state, { id: componentRef })); + }); const summaryPageName = useAppSelector((state) => state.formLayout.uiConfig.currentView); const changeText = useAppSelector( (state) => @@ -161,7 +166,7 @@ export function SummaryComponent({ id, grid, ...summaryProps }: ISummaryComponen md={displayGrid?.md || false} lg={displayGrid?.lg || false} xl={displayGrid?.xl || false} - data-testid='summary-component' + data-testid={`summary-${id}`} > { } as unknown as ILayoutEntry, ]; renderForm(summaryComponent as ILayout); - expect(screen.getByTestId('summary-component')).toBeInTheDocument(); + expect(screen.getByTestId('summary-the-summary')).toBeInTheDocument(); }); function renderForm(layout = mockComponents, customState: PreloadedState = {}) { diff --git a/test/cypress/e2e/integration/app-frontend/components.js b/test/cypress/e2e/integration/app-frontend/components.js index c7731391a9..9a03494d58 100644 --- a/test/cypress/e2e/integration/app-frontend/components.js +++ b/test/cypress/e2e/integration/app-frontend/components.js @@ -31,7 +31,7 @@ describe('UI Components', () => { }); it('is possible to upload and delete attachments', () => { - cy.goto('changeName'); + cy.goto('changename'); cy.get(appFrontend.changeOfName.uploadDropZone).should('be.visible'); cy.get(appFrontend.changeOfName.upload).selectFile('e2e/fixtures/test.pdf', { force: true }); cy.get(appFrontend.changeOfName.uploadedTable).should('be.visible'); @@ -43,7 +43,7 @@ describe('UI Components', () => { }); it('is possible to upload attachments with tags', () => { - cy.goto('changeName'); + cy.goto('changename'); cy.intercept('POST', '**/tags').as('saveTags'); cy.get(appFrontend.changeOfName.uploadWithTag.uploadZone).selectFile('e2e/fixtures/test.pdf', { force: true }); cy.get(appFrontend.changeOfName.uploadWithTag.editWindow).should('be.visible'); @@ -60,7 +60,7 @@ describe('UI Components', () => { }); it('is possible to navigate between pages using navigation bar', () => { - cy.goto('changeName'); + cy.goto('changename'); cy.get(appFrontend.navMenu) .should('be.visible') .find('li > button') @@ -87,7 +87,7 @@ describe('UI Components', () => { }); it('address component fetches post place from zip code', () => { - cy.goto('changeName'); + cy.goto('changename'); cy.get(appFrontend.changeOfName.address.street_name).should('be.visible').type('Sesame Street 1A').blur(); cy.get(appFrontend.changeOfName.address.zip_code).should('be.visible').type('0174').blur(); cy.get(appFrontend.changeOfName.address.post_place).should('have.value', 'OSLO'); @@ -102,7 +102,7 @@ describe('UI Components', () => { component.readOnly = ['equals', ['component', 'newMiddleName'], 'radio_readOnly']; } }); - cy.goto('changeName'); + cy.goto('changename'); cy.get(appFrontend.changeOfName.newFirstName).type('Per'); cy.get(appFrontend.changeOfName.newLastName).type('Hansen'); cy.get(appFrontend.changeOfName.confirmChangeName).click(); diff --git a/test/cypress/e2e/integration/app-frontend/dynamics.js b/test/cypress/e2e/integration/app-frontend/dynamics.js index b7b591a6fc..0cb333ebab 100644 --- a/test/cypress/e2e/integration/app-frontend/dynamics.js +++ b/test/cypress/e2e/integration/app-frontend/dynamics.js @@ -8,7 +8,7 @@ const appFrontend = new AppFrontend(); describe('Dynamics', () => { it('Show and hide confirm name change checkbox on changing firstname', () => { - cy.goto('changeName'); + cy.goto('changename'); cy.get(appFrontend.changeOfName.newFirstName) .should('be.visible') .type('test') @@ -25,7 +25,7 @@ describe('Dynamics', () => { }); it('Show and hide name change reasons radio buttons', () => { - cy.goto('changeName'); + cy.goto('changename'); cy.get(appFrontend.changeOfName.newFirstName).should('be.visible').type('test'); cy.get(appFrontend.changeOfName.newLastName).should('be.visible').type('test'); cy.get(appFrontend.changeOfName.confirmChangeName).should('be.visible').find('input').check(); @@ -42,7 +42,7 @@ describe('Dynamics', () => { ]; } }); - cy.goto('changeName'); + cy.goto('changename'); cy.get(appFrontend.changeOfName.newFirstName).type('test'); cy.get(appFrontend.errorReport) .should('exist') @@ -85,7 +85,7 @@ describe('Dynamics', () => { ]; }, ); - cy.goto('changeName'); + cy.goto('changename'); // Make sure the summary page can be hidden cy.get(appFrontend.navMenu).find('li > button').should('have.length', 2); diff --git a/test/cypress/e2e/integration/app-frontend/formatting.js b/test/cypress/e2e/integration/app-frontend/formatting.js index ad8498c0c8..d10b2f11e3 100644 --- a/test/cypress/e2e/integration/app-frontend/formatting.js +++ b/test/cypress/e2e/integration/app-frontend/formatting.js @@ -10,7 +10,7 @@ const mui = new Common(); describe('Formatting', () => { it('Number formatting', () => { - cy.goto('changeName'); + cy.goto('changename'); cy.get('#form-content-newFirstName').siblings().should('have.class', 'MuiGrid-grid-md-6'); cy.get('#form-content-newFirstName') .siblings() @@ -20,7 +20,7 @@ describe('Formatting', () => { .should('be.visible') .type('44444444') .should('have.value', '+47 444 44 444'); - cy.gotoAndComplete('changeName'); + cy.gotoAndComplete('changename'); cy.get(appFrontend.backButton).should('be.visible'); cy.intercept('**/api/layoutsettings/group').as('getLayoutGroup'); cy.get(appFrontend.sendinButton).should('be.visible').click(); diff --git a/test/cypress/e2e/integration/app-frontend/likert.js b/test/cypress/e2e/integration/app-frontend/likert.js index 51da869b57..7b3e52df5a 100644 --- a/test/cypress/e2e/integration/app-frontend/likert.js +++ b/test/cypress/e2e/integration/app-frontend/likert.js @@ -24,7 +24,7 @@ describe('Likert', () => { likertPage.selectRadio(likertPage.optionalQuestions[0], likertPage.options[2]); likertPage.selectRadio(likertPage.optionalQuestions[1], likertPage.options[1]); likertPage.selectRadio(likertPage.optionalQuestions[2], likertPage.options[1]); - cy.get('[data-testid=summary-component]').should(($summary) => { + cy.get('[data-testid=summary-summary-1]').should(($summary) => { const text = $summary.text(); expect(text).to.contain(likertPage.optionalTableTitle); expect(text).to.contain(likertPage.optionalQuestions[0] + ' : ' + likertPage.options[2]); diff --git a/test/cypress/e2e/integration/app-frontend/mobile.js b/test/cypress/e2e/integration/app-frontend/mobile.js index 919be70303..15761b4ff6 100644 --- a/test/cypress/e2e/integration/app-frontend/mobile.js +++ b/test/cypress/e2e/integration/app-frontend/mobile.js @@ -16,9 +16,9 @@ describe('Mobile', () => { }); it('is possible to submit app instance from mobile', () => { - cy.goto('changeName'); + cy.goto('changename'); cy.get(appFrontend.changeOfName.oldFullName).parents().eq(2).should('have.css', 'max-width', '100%'); - cy.gotoAndComplete('changeName'); + cy.gotoAndComplete('changename'); cy.intercept('**/api/layoutsettings/group').as('getLayoutGroup'); cy.get(appFrontend.sendinButton) .should('be.visible') diff --git a/test/cypress/e2e/integration/app-frontend/options.js b/test/cypress/e2e/integration/app-frontend/options.js index 7da3f8c650..7819436efa 100644 --- a/test/cypress/e2e/integration/app-frontend/options.js +++ b/test/cypress/e2e/integration/app-frontend/options.js @@ -10,7 +10,7 @@ const mui = new Common(); describe('Options', () => { it('is possible to retrieve options dynamically', () => { - cy.goto('changeName'); + cy.goto('changename'); // Case: options are dynamically refetched based on what the user selects as source cy.get(appFrontend.changeOfName.sources).should('be.visible'); diff --git a/test/cypress/e2e/integration/app-frontend/prefill.js b/test/cypress/e2e/integration/app-frontend/prefill.js index 689da72d8a..b512e49661 100644 --- a/test/cypress/e2e/integration/app-frontend/prefill.js +++ b/test/cypress/e2e/integration/app-frontend/prefill.js @@ -11,7 +11,7 @@ describe('Prefill', () => { && Cypress.env('environment') !== 'local' ? Cypress.env('externalUserFullName') : Cypress.env('userFullName'); - cy.goto('changeName'); + cy.goto('changename'); cy.get(appFrontend.changeOfName.currentName).then((name) => { cy.get(name).should('be.visible').and('have.value', userFullName).and('have.attr', 'readonly'); }); diff --git a/test/cypress/e2e/integration/app-frontend/rules.js b/test/cypress/e2e/integration/app-frontend/rules.js index 99c38a7435..63aac35ce5 100644 --- a/test/cypress/e2e/integration/app-frontend/rules.js +++ b/test/cypress/e2e/integration/app-frontend/rules.js @@ -7,7 +7,7 @@ const appFrontend = new AppFrontend(); describe('Rules', () => { it('Rule is run and new name is a concatenated string', () => { - cy.goto('changeName'); + cy.goto('changename'); cy.get(appFrontend.changeOfName.newFirstName).type('automation'); cy.get(appFrontend.changeOfName.newMiddleName).type('is'); cy.get(appFrontend.changeOfName.newLastName) @@ -23,7 +23,7 @@ describe('Rules', () => { }); it('Rule is run when a backend calculation updates a relevant field', () => { - cy.goto('changeName'); + cy.goto('changename'); // We update newLastName which triggers a calculation backend that updates NewMiddleName to 'MiddleNameFromCalculation' // This should then trigger function which concatenates first + middle + last name to the newFullName field cy.get(appFrontend.changeOfName.newLastName).should('be.visible').type('LastName').blur(); diff --git a/test/cypress/e2e/integration/app-frontend/summary.js b/test/cypress/e2e/integration/app-frontend/summary.js index a5795c6b7e..4b4c87d467 100644 --- a/test/cypress/e2e/integration/app-frontend/summary.js +++ b/test/cypress/e2e/integration/app-frontend/summary.js @@ -10,11 +10,16 @@ const mui = new Common(); describe('Summary', () => { it('Summary of change name form', () => { - cy.gotoAndComplete('changeName'); + cy.interceptLayout('changename', (component) => { + if (component.id === 'changeNameFrom') { + component.hidden = ['equals', ['component', 'newFirstName'], 'hidePrevName']; + } + }); + cy.gotoAndComplete('changename'); cy.get(appFrontend.backButton).should('be.visible'); - //Summary displays change button for editable fields and does not for readonly fields - //navigate back to form and clear date + // Summary displays change button for editable fields and does not for readonly fields + // navigate back to form and clear date cy.get(appFrontend.changeOfName.summaryNameChanges) .should('be.visible') .then((summary) => { @@ -43,7 +48,7 @@ describe('Summary', () => { }); }); - //Summary of attachment components + // Summary of attachment components cy.get(appFrontend.changeOfName.summaryNameChanges) .should('exist') .siblings() @@ -59,8 +64,8 @@ describe('Summary', () => { .and('contain.text', 'Adresse'); }); - //Summary displays error when required field is not filled - //Navigate to form and fill the required field + // Summary displays error when required field is not filled + // Navigate to form and fill the required field cy.get(appFrontend.changeOfName.summaryNameChanges) .should('exist') .siblings() @@ -79,7 +84,7 @@ describe('Summary', () => { }); }); - //Error in summary field is removed when the required field is filled + // Error in summary field is removed when the required field is filled cy.get(appFrontend.changeOfName.summaryNameChanges) .should('exist') .siblings() @@ -87,7 +92,15 @@ describe('Summary', () => { .then((summaryDate) => { cy.get(summaryDate).contains(texts.dateOfEffect).should('not.have.css', 'color', 'rgb(213, 32, 59)'); cy.get(summaryDate).contains(mui.gridContainer, texts.requiredFieldDateFrom).should('not.exist'); + }); + + // Hide the component the Summary refers to, which should hide the summary component as well + cy.get('[data-testid=summary-summary-1]').contains('span', 'Du har valgt å endre:').should('be.visible'); + cy.get(appFrontend.navMenu).find('li > button').first().click(); + cy.get(appFrontend.changeOfName.newFirstName).clear().type('hidePrevName'); + cy.get(appFrontend.navMenu).find('li > button').last().click(); + cy.get('[data-testid=summary-summary-1]').should('not.exist'); }); it('is possible to view summary of repeating group', () => { @@ -122,8 +135,21 @@ describe('Summary', () => { .find(appFrontend.group.editContainer) .find(appFrontend.group.next).click(); cy.get(appFrontend.group.rows[0].nestedGroup.rows[0].nestedDynamics).click(); - cy.get(appFrontend.group.rows[0].nestedGroup.rows[0].nestedOptions[1]).click(); - cy.get(appFrontend.group.rows[0].nestedGroup.rows[0].nestedOptions[2]).click(); + + const workAroundSlowSave = JSON.parse('true'); + if (workAroundSlowSave) { + // Blurring each of these works around a problem where clicking these too fast will overwrite the immedateState + // value in useDelayedSaveState(). This is a fundamental problem with the useDelayedSaveState() functionality, + // and in the future we should fix this properly by simplifying to save data immediately in the redux state + // but delay the PUT request instead. + // See https://github.com/Altinn/app-frontend-react/issues/339#issuecomment-1321920974 + cy.get(appFrontend.group.rows[0].nestedGroup.rows[0].nestedOptions[1]).check().blur(); + cy.get(appFrontend.group.rows[0].nestedGroup.rows[0].nestedOptions[2]).check().blur(); + } else { + cy.get(appFrontend.group.rows[0].nestedGroup.rows[0].nestedOptions[1]).check(); + cy.get(appFrontend.group.rows[0].nestedGroup.rows[0].nestedOptions[2]).check(); + } + cy.get(appFrontend.group.rows[0].nestedGroup.saveBtn).click(); cy.get(appFrontend.group.saveMainGroup).click(); cy.contains(mui.button, texts.backToSummary).click(); @@ -139,5 +165,12 @@ describe('Summary', () => { cy.get(item).eq(5).should('contain.text', texts.nestedOptions); cy.get(item).eq(5).should('contain.text', `${texts.nestedOption2}, ${texts.nestedOption3}`); }); + + // Hiding the group should hide the group summary as well + cy.get('[data-testid=summary-summary-1]').should('be.visible'); + cy.get(appFrontend.navMenu).find('li > button').eq(1).click(); + cy.get(appFrontend.group.showGroupToContinue).find('input[type=checkbox]').uncheck(); + cy.get(appFrontend.navMenu).find('li > button').last().click(); + cy.get('[data-testid=summary-summary-1]').should('not.exist'); }); }); diff --git a/test/cypress/e2e/integration/app-frontend/tabbing.js b/test/cypress/e2e/integration/app-frontend/tabbing.js index 019df51d96..7f29366ef6 100644 --- a/test/cypress/e2e/integration/app-frontend/tabbing.js +++ b/test/cypress/e2e/integration/app-frontend/tabbing.js @@ -7,7 +7,7 @@ const appFrontend = new AppFrontend(); describe('Tabbing', () => { it('Tab through the fields in change name form', () => { - cy.goto('changeName'); + cy.goto('changename'); cy.get(appFrontend.changeOfName.newFirstName).focus().tab(); cy.focused().should('have.attr', 'id').and('eq', appFrontend.changeOfName.newLastName.substring(1)); cy.get(appFrontend.changeOfName.newLastName).type('a').blur().tab().tab().tab(); diff --git a/test/cypress/e2e/integration/app-frontend/texts.js b/test/cypress/e2e/integration/app-frontend/texts.js index d6fc031627..908fb036c6 100644 --- a/test/cypress/e2e/integration/app-frontend/texts.js +++ b/test/cypress/e2e/integration/app-frontend/texts.js @@ -7,7 +7,7 @@ const appFrontend = new AppFrontend(); describe('Texts', () => { beforeEach(() => { - cy.goto('changeName'); + cy.goto('changename'); }); it('Variable in texts work and are updated if the variable is updated with a calculation backend', () => { diff --git a/test/cypress/e2e/integration/app-frontend/validation.js b/test/cypress/e2e/integration/app-frontend/validation.js index 3fb1654435..a7df7eb308 100644 --- a/test/cypress/e2e/integration/app-frontend/validation.js +++ b/test/cypress/e2e/integration/app-frontend/validation.js @@ -10,7 +10,7 @@ const mui = new Common(); describe('Validation', () => { it('Required field validation should be visible on submit, not on blur', () => { - cy.goto('changeName'); + cy.goto('changename'); // This field has server-side validations marking it as required, overriding the frontend validation functionality // which normally postpones the empty fields validation until the page validation runs. We need to type something, @@ -78,7 +78,7 @@ describe('Validation', () => { }); it('Custom field validation - error', () => { - cy.goto('changeName'); + cy.goto('changename'); cy.intercept('GET', '**/validate').as('validateData'); cy.get(appFrontend.changeOfName.newFirstName).should('be.visible').type('test').blur(); cy.wait('@validateData'); @@ -92,7 +92,7 @@ describe('Validation', () => { }); it('Soft validation - warning', () => { - cy.goto('changeName'); + cy.goto('changename'); cy.intercept('GET', '**/validate').as('validateData'); cy.get(appFrontend.changeOfName.newMiddleName).should('be.visible').type('test').blur(); cy.wait('@validateData'); @@ -103,7 +103,7 @@ describe('Validation', () => { }); it('Soft validation - info', () => { - cy.goto('changeName'); + cy.goto('changename'); cy.intercept('GET', '**/validate').as('validateData'); cy.get(appFrontend.changeOfName.newMiddleName).should('be.visible').type('info').blur(); cy.wait('@validateData'); @@ -114,7 +114,7 @@ describe('Validation', () => { }); it('Soft validation - success', () => { - cy.goto('changeName'); + cy.goto('changename'); cy.intercept('GET', '**/validate').as('validateData'); cy.get(appFrontend.changeOfName.newMiddleName).should('be.visible').type('success').blur(); cy.wait('@validateData'); @@ -125,7 +125,7 @@ describe('Validation', () => { }); it('Page validation on clicking next', () => { - cy.goto('changeName'); + cy.goto('changename'); cy.get(appFrontend.changeOfName.newFirstName).should('be.visible').clear().type('test').blur(); cy.get(appFrontend.changeOfName.confirmChangeName).should('be.visible').find('input').check(); cy.intercept('GET', '**/validate').as('validateData'); @@ -176,7 +176,7 @@ describe('Validation', () => { }); it('Validation on uploaded attachment type', () => { - cy.goto('changeName'); + cy.goto('changename'); cy.get(appFrontend.changeOfName.upload).selectFile('e2e/fixtures/test.png', { force: true }); cy.get(appFrontend.fieldValidationError.replace('field', appFrontend.changeOfName.upload.substring(1))) .should('exist') @@ -185,7 +185,7 @@ describe('Validation', () => { }); it('Client side validation from json schema', () => { - cy.goto('changeName'); + cy.goto('changename'); cy.get(appFrontend.changeOfName.newLastName).should('be.visible').type('client').blur(); cy.get(appFrontend.fieldValidationError.replace('field', appFrontend.changeOfName.newLastName.substring(1))) .should('exist') diff --git a/test/cypress/e2e/support/index.d.ts b/test/cypress/e2e/support/index.d.ts index 7fd3ac225c..123df6ffeb 100644 --- a/test/cypress/e2e/support/index.d.ts +++ b/test/cypress/e2e/support/index.d.ts @@ -1,6 +1,6 @@ /// -export type FrontendTestTask = 'message' | 'changeName' | 'group' | 'likert' | 'confirm'; +export type FrontendTestTask = 'message' | 'changename' | 'group' | 'likert' | 'confirm'; export type GotoMode = 'fast' | 'with-data'; declare namespace Cypress { @@ -87,7 +87,7 @@ declare namespace Cypress { * Must be called in the beginning of your test. */ interceptLayout( - layoutName: string, + layoutName: FrontendTestTask | string, mutator: (component: any) => void, wholeLayoutMutator?: (layoutSet: any) => void, ): Chainable; diff --git a/test/cypress/e2e/support/navigation.js b/test/cypress/e2e/support/navigation.js index cdc379a702..b9609943ac 100644 --- a/test/cypress/e2e/support/navigation.js +++ b/test/cypress/e2e/support/navigation.js @@ -14,7 +14,7 @@ const mui = new Common(); * when using goto(..., 'fast') */ const validMinimalData = { - changeName: { + changename: { 'skjemanummer': '1533', 'spesifikasjonsnummer': '11172', 'blankettnummer': 'RF-1453', @@ -76,7 +76,7 @@ const completeFormFast = { completeFormSlow.message(); genericSendIn(); }, - changeName: () => endTaskWithData(validMinimalData.changeName), + changename: () => endTaskWithData(validMinimalData.changename), group: () => { endTaskWithData(validMinimalData.group); }, @@ -103,7 +103,7 @@ const completeFormSlow = { cy.wait('@createInstance'); cy.get(appFrontend.closeButton).should('be.visible'); }, - changeName: () => { + changename: () => { cy.get(appFrontend.changeOfName.currentName) .should('be.visible') .then(() => { @@ -173,7 +173,7 @@ const completeFormSlow = { const sendInTask = { message: genericSendIn, - changeName: genericSendIn, + changename: genericSendIn, group: genericSendIn, likert: genericSendIn, confirm: genericSendIn,