Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
2ec43f6
Logging in using Tenor users by default, cleaning up the now non-work…
Jun 2, 2026
bc25440
Skipping tests for self-identified-user
Jun 2, 2026
173ac12
Waiting some more before continuing, so that tests don't randomly fai…
Jun 2, 2026
20ea82d
This little intercept messed up the party-selection tests pretty badly..
Jun 2, 2026
8939887
Fixing party-selection.ts test for both tt02 and local
Jun 2, 2026
e62c561
Fixing stateless-app/party-selection.ts
Jun 2, 2026
961f1a0
Updating test assertions now that we save the 'gwTask' field in the g…
Jun 2, 2026
d1233b6
This exists, but is not visible. Seems like this started failing when…
Jun 2, 2026
ac2d954
Most places assumes no party-selection, it's just the party-selection…
Jun 2, 2026
c9f6cee
Adding a command for preventing party selection
Jun 3, 2026
555352d
Turns out the URL here was wrong
Jun 3, 2026
7d42696
Fixing origin problems during login with Tenor by visiting a simple p…
Jun 3, 2026
5fd028c
Fixing 'cypress run' tests, as they did not work with the accessible …
Jun 3, 2026
cc63775
Fixing anonymous stateless app tests
Jun 3, 2026
55ff285
Changing the default user to avoid having to pepper cy.preventPartySe…
Jun 3, 2026
5ddda6d
Refactoring and fixes to make double-signing.ts work on tt02 with a s…
Jun 3, 2026
b4eb24a
I broke the JSON
Jun 3, 2026
170e8b3
This did not work in mobile.ts, but that doesn't matter as long as we…
Jun 3, 2026
b26a744
Possibly fixing some pdf tests by visiting the page via the login.htm…
Jun 3, 2026
288702e
Updating tests that checks names
Jun 4, 2026
3614968
Removing print-button test. This fails now because cy.stub() no longe…
Jun 4, 2026
0570e09
Fixing intercept now that the message step is called first
Jun 4, 2026
33c200d
This seems to fix the flakiness issue where readyForPrint hangs on fe…
Jun 4, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion test/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ npx cypress run --env environment=tt02 -s 'test/e2e/integration/*/*.ts'
- [ttd/signering-brukerstyrt](https://altinn.studio/repos/ttd/signering-brukerstyrt)
- [ttd/signing-test](https://dev.altinn.studio/repos/ttd/signing-test)
- [ttd/stateless-app](https://dev.altinn.studio/repos/ttd/stateless-app)
- [ttd/subform-test](https://dev.altinn.studio/repos/ttd/subform-test)
- [ttd/subform-test](https://altinn.studio/repos/ttd/subform-test)

3. Start the app you want to test:

Expand Down
4 changes: 1 addition & 3 deletions test/e2e/config/tt02.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@
"selfIdentifiedFullName": "olemartinorg",
"selfIdentifiedFirstName": "olemartinorg",
"selfIdentifiedUserName": "olemartinorg",
"selfIdentifiedUserPwd": "qkwcaDU9qsaA3iL5bgKGMLpfYdf3vzpb",

"signingPartyId": "51826033"
"selfIdentifiedUserPwd": "qkwcaDU9qsaA3iL5bgKGMLpfYdf3vzpb"
}
}
2 changes: 1 addition & 1 deletion test/e2e/integration/anonymous-stateless-app/anonymous.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const appFrontend = new AppFrontend();
describe('Anonymous (stateless)', () => {
beforeEach(() => {
cy.intercept('**/api/layoutsettings/stateless').as('getLayoutStateless');
cy.startAppInstance(appFrontend.apps.anonymousStateless, { cyUser: null });
cy.startAppInstance(appFrontend.apps.anonymousStateless, { cyUser: null, tenorUser: null });
cy.wait('@getLayoutStateless');
cy.get(appFrontend.stateless.name).should('exist').and('be.visible');
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ describe('Auto save behavior', () => {
postFormDataCounter++;
}).as('putFormData');
cy.interceptLayoutSetsUiSettings({ autoSaveBehavior: 'onChangeFormData' });
cy.startAppInstance(appFrontend.apps.anonymousStateless, { cyUser: null });
cy.startAppInstance(appFrontend.apps.anonymousStateless, { cyUser: null, tenorUser: null });

cy.get(appFrontend.stateless.name).type('Per');
cy.wait('@putFormData').then(() => {
Expand All @@ -30,7 +30,7 @@ describe('Auto save behavior', () => {
postFormDataCounter++;
}).as('putFormData');
cy.interceptLayoutSetsUiSettings({ autoSaveBehavior: 'onChangePage' });
cy.startAppInstance(appFrontend.apps.anonymousStateless, { cyUser: null });
cy.startAppInstance(appFrontend.apps.anonymousStateless, { cyUser: null, tenorUser: null });

cy.get(appFrontend.stateless.name).type('Per');
// Doing a hard wait to be sure no request is sent to backend
Expand Down
2 changes: 1 addition & 1 deletion test/e2e/integration/anonymous-stateless-app/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const appFrontend = new AppFrontend();
describe('Anonymous (stateless) - Options', () => {
it('should support fetching option list and changing its value', () => {
cy.intercept('**/api/layoutsettings/stateless').as('getLayoutStateless');
cy.startAppInstance(appFrontend.apps.anonymousStateless, { cyUser: null });
cy.startAppInstance(appFrontend.apps.anonymousStateless, { cyUser: null, tenorUser: null });
cy.wait('@getLayoutStateless');

const dropdownComponent = appFrontend.stateless.dropdown;
Expand Down
2 changes: 1 addition & 1 deletion test/e2e/integration/anonymous-stateless-app/validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const appFrontend = new AppFrontend();

describe('Validation in anonymous stateless app', () => {
it('Should show validation message for missing name', () => {
cy.startAppInstance(appFrontend.apps.anonymousStateless, { cyUser: null });
cy.startAppInstance(appFrontend.apps.anonymousStateless, { cyUser: null, tenorUser: null });
cy.get(appFrontend.stateless.name).should('exist').and('be.visible');
cy.get(appFrontend.stateless.name).invoke('val').should('be.empty');
cy.get(appFrontend.navButtons).contains('button', 'next').click();
Expand Down
2 changes: 1 addition & 1 deletion test/e2e/integration/frontend-test/accordion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ describe('Accordion', () => {

const accordionContent = /in horas tendebat resumptis/i;

cy.findByText(accordionContent).should('not.exist');
cy.findByText(accordionContent).should('not.be.visible');
cy.findByRole('button', { name: /mer informasjon vedrørende navneendring/i }).click();
cy.findByText(accordionContent).should('be.visible');
});
Expand Down
20 changes: 10 additions & 10 deletions test/e2e/integration/frontend-test/auto-save-behavior.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,18 @@ describe('Auto save behavior', () => {
cy.goto('group');

cy.findByRole('checkbox', { name: appFrontend.group.prefill.liten }).check();
cy.get('@saveFormData.all').should('have.length', 1);
cy.get('@saveFormData.all').should('have.length', 2);

cy.findByRole('button', { name: 'Neste' }).clickAndGone();
cy.get('@saveFormData.all').should('have.length', 2); // The row has a fiels with preselectedOptionIndex
cy.get('@saveFormData.all').should('have.length', 3); // The row has a fiels with preselectedOptionIndex
cy.findByRole('button', { name: 'Forrige' }).clickAndGone();

// Doing an extra wait to be sure no request is sent to backend
cy.waitUntilSaved();
cy.waitForNetworkIdle(100);
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(100);
cy.get('@saveFormData.all').should('have.length', 2);
cy.get('@saveFormData.all').should('have.length', 3);
});

it('onChangePage: Should not save form when interacting with form element(checkbox), but should save on navigating between pages', () => {
Expand All @@ -37,11 +37,11 @@ describe('Auto save behavior', () => {
// Doing a hard wait to be sure no request is sent to backend
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(1000);
cy.get('@saveFormData.all').should('have.length', 0);
cy.get('@saveFormData.all').should('have.length', 1);

// At this point we've saved the prefill value (1).
cy.findByRole('button', { name: 'Neste' }).clickAndGone();
cy.get('@saveFormData.all').should('have.length', 1);
cy.get('@saveFormData.all').should('have.length', 2);

// Clicking the back button does not save anything, because we didn't
// change anything in the form data worth saving
Expand All @@ -55,34 +55,34 @@ describe('Auto save behavior', () => {

// At some point when we got the reply back we saw that one of those new rows should have a preselectedOptionIndex,
// so that gets set and saved as well during a page navigation (2).
cy.get('@saveFormData.all').should('have.length', 2);
cy.get('@saveFormData.all').should('have.length', 3);

cy.get(appFrontend.group.showGroupToContinue).findByRole('checkbox', { name: 'Ja' }).check();
cy.get(appFrontend.group.mainGroup).should('be.visible');

// We have now clicked 'Ja' to show the repeating group (3)
cy.findByRole('button', { name: 'Forrige' }).clickAndGone();
cy.get('@saveFormData.all').should('have.length', 3);
cy.get('@saveFormData.all').should('have.length', 4);

// NavigationBar
cy.findByRole('checkbox', { name: appFrontend.group.prefill.middels }).check();

// Now we've added 'middels' (4)
cy.gotoNavPage('repeating');
cy.get('@saveFormData.all').should('have.length', 4);
cy.get('@saveFormData.all').should('have.length', 5);

// Icon previous button
cy.get(appFrontend.group.showGroupToContinue).findByRole('checkbox', { name: 'Ja' }).uncheck();

// Now we've unchecked 'ja' and added a preselectedOptionIndex for the new row (5)
cy.findByRole('button', { name: 'Forrige' }).clickAndGone();
cy.get('@saveFormData.all').should('have.length', 5);
cy.get('@saveFormData.all').should('have.length', 6);

// Doing a hard wait to be sure no request is sent to backend
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(1000);
cy.waitUntilSaved();
cy.get('@saveFormData.all').should('have.length', 5);
cy.get('@saveFormData.all').should('have.length', 6);
});

(['current', 'all'] as const).forEach((pages) => {
Expand Down
7 changes: 4 additions & 3 deletions test/e2e/integration/frontend-test/instantiation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { v4 as uuidv4 } from 'uuid';

import { AppFrontend } from 'test/e2e/pageobjects/app-frontend';
import { cyMockResponses } from 'test/e2e/pageobjects/party-mocks';
import { Tenor } from 'test/e2e/support/users';

import type { IncomingApplicationMetadata } from 'src/features/applicationMetadata/types';
import type { InstantiationValidationResult } from 'src/features/instantiate/InstantiationValidation';
Expand All @@ -14,14 +15,14 @@ describe('Instantiation', () => {
const invalidParty =
Cypress.env('type') === 'localtest'
? /950474084/ // Localtest: Oslos Vakreste borettslag
: /310732001/; // TT02: Søvnig Impulsiv Tiger AS
: /314277961/; // TT02: Offisiell Virtuell Tiger AS

it('should show an error message when going directly to instantiation', () => {
cyMockResponses({
doNotPromptForParty: false,
onEntryShow: 'new-instance',
});
cy.startAppInstance(appFrontend.apps.frontendTest, { cyUser: 'manager' });
cy.startAppInstance(appFrontend.apps.frontendTest, { cyUser: 'manager', tenorUser: Tenor.users.snaalDugnad });
cy.findByRole('button', { name: invalidParty }).click();

cy.findByText('Du kan ikke starte denne tjenesten').should('be.visible');
Expand All @@ -37,7 +38,7 @@ describe('Instantiation', () => {
{ id: 'def456', lastChanged: '2023-01-02T00:00:00.000Z', lastChangedBy: 'user' },
],
});
cy.startAppInstance(appFrontend.apps.frontendTest, { cyUser: 'manager' });
cy.startAppInstance(appFrontend.apps.frontendTest, { cyUser: 'manager', tenorUser: Tenor.users.snaalDugnad });
cy.findByRole('button', { name: invalidParty }).click();

cy.findByText('Du har allerede startet å fylle ut dette skjemaet.').should('be.visible');
Expand Down
117 changes: 70 additions & 47 deletions test/e2e/integration/frontend-test/party-selection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import texts from 'test/e2e/fixtures/texts.json';
import { AppFrontend } from 'test/e2e/pageobjects/app-frontend';
import { cyMockResponses, CyPartyMocks, removeAllButKeepOrg } from 'test/e2e/pageobjects/party-mocks';
import { cyUserCredentials } from 'test/e2e/support/auth';
import { Tenor } from 'test/e2e/support/users';
import type { CyUser } from 'test/e2e/support/auth';

import type { IParty } from 'src/types/shared';

Expand All @@ -10,7 +12,8 @@ const appFrontend = new AppFrontend();
// Org numbers the accountant test user only represents as accountant — no instantiate rights, so
// instantiation returns 403.
const NonInstantiableOrgForAccountant = {
AldrendeOppstemtTigerAS: '213611372',
DdgFitness: '897069650',
StabilSmulApe: '313252698',
} as const;

describe('Party selection', () => {
Expand Down Expand Up @@ -123,44 +126,38 @@ describe('Party selection', () => {
});
});

[false].forEach((doNotPromptForParty) => {
it(`${
doNotPromptForParty ? 'Does not prompt' : 'Prompts'
} for party when doNotPromptForParty = ${doNotPromptForParty}, on instantiation with multiple possible parties`, () => {
cyMockResponses({
allowedToInstantiate: (parties) => [...parties, CyPartyMocks.ExamplePerson1],
doNotPromptForParty,
});
cy.startAppInstance(appFrontend.apps.frontendTest);
it(`Prompts for party when doNotPromptForParty = false, on instantiation with multiple possible parties`, () => {
cyMockResponses({
allowedToInstantiate: (parties) => [...parties, CyPartyMocks.ExamplePerson1],
doNotPromptForParty: false,
});
cy.startAppInstance(appFrontend.apps.frontendTest, { tenorUser: Tenor.users.humanAndrefiolin });

if (!doNotPromptForParty) {
cy.get(appFrontend.partySelection.appHeader).should('be.visible');
cy.get('[id^="party-"]').should('be.visible');
cy.findByRole('heading', { name: 'Hvorfor ser jeg dette?' }).should('be.visible');
cy.findByRole('heading', { name: 'Hvorfor ser jeg dette?' })
.siblings('p')
.first()
.should(
'contain.text',
'Du kan endre profilinnstillingene dine for å ikke bli spurt om aktør hver gang du starter utfylling av et nytt skjema.',
);
cy.findByRole('heading', { name: 'Appen for test av app frontend' }).should('not.exist');
cy.get(appFrontend.partySelection.appHeader).should('be.visible');
cy.get('[id^="party-"]').should('be.visible');
cy.findByRole('heading', { name: 'Hvorfor ser jeg dette?' }).should('be.visible');
cy.findByRole('heading', { name: 'Hvorfor ser jeg dette?' })
.siblings('p')
.first()
.should(
'contain.text',
'Du kan endre profilinnstillingene dine for å ikke bli spurt om aktør hver gang du starter utfylling av et nytt skjema.',
);
cy.findByRole('heading', { name: 'Appen for test av app frontend' }).should('not.exist');

cy.visualTesting('reportee-selection');
cy.visualTesting('reportee-selection');

cy.get('[id^="party-"]').eq(0).click();
}
clickValidParty('default');

cy.get(appFrontend.appHeader).should('be.visible');
cy.findByRole('heading', { name: 'Appen for test av app frontend' }).should('be.visible');
cy.get('[id^="party-"]').should('not.exist');
cy.get(appFrontend.appHeader).should('be.visible');
cy.findByRole('heading', { name: 'Appen for test av app frontend' }).should('be.visible');
cy.get('[id^="party-"]').should('not.exist');

// Test that it goes straight in when accessing an existing instance
cy.reloadAndWait();
// Test that it goes straight in when accessing an existing instance
cy.reloadAndWait();

cy.findByRole('heading', { name: 'Appen for test av app frontend' }).should('be.visible');
cy.get('[id^="party-"]').should('not.exist');
});
cy.findByRole('heading', { name: 'Appen for test av app frontend' }).should('be.visible');
cy.get('[id^="party-"]').should('not.exist');
});

[true, false].forEach((doNotPromptForParty) => {
Expand All @@ -186,7 +183,11 @@ describe('Party selection', () => {
(req) => {
req.on('response', (res) => {
const parties = res.body as IParty[];
correctParty = parties[0]; // parties.find((party: IParty) => party.partyId == partyId);
if (Cypress.env('type') === 'localtest') {
correctParty = parties.find((party) => party.name === cyUserCredentials.default.displayName);
} else {
correctParty = parties.find((party) => party.name === Tenor.users.humanAndrefiolin.name.toUpperCase());
}
if (!correctParty) {
throw new Error(`No parties returned from api`);
}
Expand All @@ -212,7 +213,10 @@ describe('Party selection', () => {
},
);

cy.startAppInstance(appFrontend.apps.frontendTest, { cyUser: 'default' });
cy.startAppInstance(appFrontend.apps.frontendTest, {
cyUser: 'default',
tenorUser: Tenor.users.humanAndrefiolin,
});
cy.get(appFrontend.appHeader).should('be.visible');
cy.get('[id^="party-"]').should('not.exist');

Expand All @@ -230,7 +234,10 @@ describe('Party selection', () => {
appPromptForPartyOverride,
allowedToInstantiate: (parties) => [...parties, CyPartyMocks.ExamplePerson1],
});
cy.startAppInstance(appFrontend.apps.frontendTest, { cyUser: 'default' });
cy.startAppInstance(appFrontend.apps.frontendTest, {
cyUser: 'default',
tenorUser: Tenor.users.humanAndrefiolin,
});

if (appPromptForPartyOverride === 'always') {
cy.get(appFrontend.partySelection.appHeader).should('be.visible');
Expand All @@ -242,7 +249,7 @@ describe('Party selection', () => {
.should('contain.text', 'Denne appen er satt opp til å alltid spørre om aktør.');
cy.findByRole('heading', { name: 'Appen for test av app frontend' }).should('not.exist');

cy.get('[id^="party-"]').eq(0).click();
clickValidParty('default');
}

cy.get(appFrontend.appHeader).should('be.visible');
Expand All @@ -254,18 +261,29 @@ describe('Party selection', () => {

it('Should be possible to select another party if instantiation fails, and go back to party selection and instantiate again', () => {
cy.allowFailureOnEnd();
const user = cyUserCredentials.accountant.firstName;
// Pin a specific org by number instead of taking the first one — the tt02 party list order is
// not stable, and an org the user *can* instantiate for may otherwise end up first.
cyMockResponses({
allowedToInstantiate: (parties) =>
allowedToInstantiate: (parties) => {
const userToKeep =
Cypress.env('type') === 'localtest'
? cyUserCredentials.accountant.displayName
: Tenor.users.humanAndrefiolin.name.toUpperCase();
const orgToKeep =
Cypress.env('type') === 'localtest'
? NonInstantiableOrgForAccountant.DdgFitness
: NonInstantiableOrgForAccountant.StabilSmulApe;
// Removing all other users as well, since one of the users are not allowed to instantiate on tt02
removeAllButKeepOrg(parties, NonInstantiableOrgForAccountant.AldrendeOppstemtTigerAS).filter(
(party) => party.orgNumber || party.name.includes(user),
),
return removeAllButKeepOrg(parties, orgToKeep).filter(
(party) => party.orgNumber || party.name.includes(userToKeep),
);
},
doNotPromptForParty: false,
});
cy.startAppInstance(appFrontend.apps.frontendTest, { cyUser: 'accountant' });
cy.startAppInstance(appFrontend.apps.frontendTest, {
cyUser: 'accountant',
tenorUser: Tenor.users.humanAndrefiolin,
});

// Select the organisation. This is not allowed to instantiate in this app, so it will throw an error.
cy.findAllByText(/org\.nr\. \d+/)
Expand All @@ -282,10 +300,7 @@ describe('Party selection', () => {
// eslint-disable-next-line cypress/no-unnecessary-waiting
cy.wait(500);

// The person on the other hand is allowed to instantiate
cy.findAllByText(/personnr\. \d+/)
.first()
.click();
clickValidParty('accountant');
cy.findByRole('heading', { name: 'Appen for test av app frontend' }).should('be.visible');

// To make sure this instance is different from the next, we navigate to the next process step in this one
Expand All @@ -308,3 +323,11 @@ describe('Party selection', () => {
cy.findByRole('heading', { name: 'Appen for test av app frontend' }).should('be.visible');
});
});

function clickValidParty(cyUser: CyUser) {
if (Cypress.env('type') === 'localtest') {
cy.findByText(cyUserCredentials[cyUser].displayName).click();
} else {
cy.findByText(Tenor.users.humanAndrefiolin.name.toUpperCase()).click();
}
}
2 changes: 1 addition & 1 deletion test/e2e/integration/frontend-test/pdf.ts
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,7 @@ describe('PDF', () => {

// Used to cause a crash, @see https://github.com/Altinn/app-frontend-react/pull/2019
it('Grid in Group should display correctly', { retries: 0 }, () => {
cy.intercept('GET', '**/layouts/**', (req) => {
cy.intercept('GET', '**/layouts/changename', (req) => {
req.on('response', (res) => {
const body: ILayoutCollection = JSON.parse(res.body);
res.send({
Expand Down
Loading
Loading