diff --git a/backend/src/Designer/Services/Implementation/AppDevelopmentService.cs b/backend/src/Designer/Services/Implementation/AppDevelopmentService.cs index 53b679ebf15..27c2419c7a6 100644 --- a/backend/src/Designer/Services/Implementation/AppDevelopmentService.cs +++ b/backend/src/Designer/Services/Implementation/AppDevelopmentService.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -305,7 +306,7 @@ public bool TryGetFrontendVersion(AltinnRepoEditingContext altinnRepoEditingCont try { - indexFilePath = altinnAppGitRepository.FindFiles(new[] { "App/Views/Home/Index.cshtml" }).FirstOrDefault(); + indexFilePath = altinnAppGitRepository.FindFiles(new[] { "App/views/Home/Index.cshtml" }).FirstOrDefault(); } catch (DirectoryNotFoundException) { diff --git a/backend/tests/Designer.Tests/Controllers/AppDevelopmentController/GetAppVersionTests.cs b/backend/tests/Designer.Tests/Controllers/AppDevelopmentController/GetAppVersionTests.cs index fe0f13d1067..0479b28cec8 100644 --- a/backend/tests/Designer.Tests/Controllers/AppDevelopmentController/GetAppVersionTests.cs +++ b/backend/tests/Designer.Tests/Controllers/AppDevelopmentController/GetAppVersionTests.cs @@ -40,7 +40,7 @@ public async Task GetAppVersion_GivenCsProjFile_ShouldReturnOK(string org, strin { "[[appLibVersion]]", backendVersion }, { "[[frontendVersion]]", frontendVersion } }; await AddCsProjToRepo("App/App.csproj", csprojTemplate, replacements); - await AddFrontendIndexToRepo("App/Views/Home/Index.cshtml", indesCshtmlTemplate, replacements); + await AddFrontendIndexToRepo("App/views/Home/Index.cshtml", indesCshtmlTemplate, replacements); string url = VersionPrefix(org, targetRepository); @@ -101,7 +101,7 @@ public async Task GetAppVersion_GivenIndexFileWithoutFrontendVersion_ShouldRetur await CopyRepositoryForTest(org, app, developer, targetRepository); await AddCsProjToRepo("App/App.csproj", csprojTemplate, new Dictionary() { { "[[appLibVersion]]", backendVersion } }); - await AddFrontendIndexToRepo("App/Views/Home/Index.cshtml", indesCshtmlTemplate); + await AddFrontendIndexToRepo("App/views/Home/Index.cshtml", indesCshtmlTemplate); string url = VersionPrefix(org, targetRepository); using var response = await HttpClient.GetAsync(url); diff --git a/frontend/testing/playwright/enum/Language.ts b/frontend/testing/playwright/enum/Language.ts new file mode 100644 index 00000000000..534640c0552 --- /dev/null +++ b/frontend/testing/playwright/enum/Language.ts @@ -0,0 +1,3 @@ +export enum Language { + Norwegian = 'Norsk', +} diff --git a/frontend/testing/playwright/helpers/BasePage.ts b/frontend/testing/playwright/helpers/BasePage.ts index e4d82924828..1b21f6b5de2 100644 --- a/frontend/testing/playwright/helpers/BasePage.ts +++ b/frontend/testing/playwright/helpers/BasePage.ts @@ -34,4 +34,12 @@ export class BasePage extends RouterRoute { return text; } + + public async waitForXAmountOfMilliseconds(milliseconds: number): Promise { + await new Promise((resolve) => + setTimeout(() => { + return resolve(''); + }, milliseconds), + ); + } } diff --git a/frontend/testing/playwright/pages/LoginPage.ts b/frontend/testing/playwright/pages/LoginPage.ts index 0cb3cc67181..c6884535e7d 100644 --- a/frontend/testing/playwright/pages/LoginPage.ts +++ b/frontend/testing/playwright/pages/LoginPage.ts @@ -1,11 +1,14 @@ import type { Page } from '@playwright/test'; import { BasePage } from '../helpers/BasePage'; +import { Language } from '../enum/Language'; // Since this page is a Razor page, it's not using the nb/en.json files, which are used in the frontend. const loginPageTexts: Record = { login: 'logg inn', username: 'Brukernavn eller epost', password: 'Passord', + error_message: 'Ugyldig brukernavn eller passord.', + links: 'Links', }; export class LoginPage extends BasePage { @@ -44,7 +47,22 @@ export class LoginPage extends BasePage { } public async checkThatErrorMessageIsVisible(): Promise { - await this.page.getByText(/ugyldig brukernavn eller passord./i).isVisible(); + await this.page.getByText(loginPageTexts['error_message']).isVisible(); + } + + public async getLanguage(): Promise { + return await this.page + .getByRole('group', { name: loginPageTexts['links'] }) + .getByRole('menu') + .innerText(); + } + + public async clickOnLanguageMenu(): Promise { + await this.page.getByRole('group', { name: loginPageTexts['links'] }).getByRole('menu').click(); + } + + public async clickOnNorwegianLanguageOption(): Promise { + await this.page.getByRole('menuitem', { name: Language.Norwegian }).click(); } public async addSessionToSharableStorage() { diff --git a/frontend/testing/playwright/playwright.config.ts b/frontend/testing/playwright/playwright.config.ts index 58289e3b3c2..6110c5bce62 100644 --- a/frontend/testing/playwright/playwright.config.ts +++ b/frontend/testing/playwright/playwright.config.ts @@ -13,8 +13,7 @@ export default defineConfig({ trace: 'on-first-retry', baseURL: process.env.PLAYWRIGHT_TEST_BASE_URL, }, - fullyParallel: true, - timeout: 3 * 60 * 1000, + fullyParallel: false, forbidOnly: !!process.env.CI, retries: process.env.CI ? 2 : 0, workers: 1, // Github actions always use only 1, so we set to 1 locally as well diff --git a/frontend/testing/playwright/tests/dashboard/dashboard.spec.ts b/frontend/testing/playwright/tests/dashboard/dashboard.spec.ts index 4b4b831b247..c5d20a80b34 100644 --- a/frontend/testing/playwright/tests/dashboard/dashboard.spec.ts +++ b/frontend/testing/playwright/tests/dashboard/dashboard.spec.ts @@ -11,16 +11,8 @@ const getExtraAppName = (appName: string): string => `extra-app-${appName}`; // Before the tests starts, we need to create the dashboard app test.beforeAll(async ({ testAppName, request, storageState }) => { - // Create 2 apps - const firstApp = await createApp(testAppName, request, storageState as StorageState); - const secondApp = await createApp( - getExtraAppName(testAppName), - request, - storageState as StorageState, - ); - - expect(firstApp.ok()).toBeTruthy(); - expect(secondApp.ok()).toBeTruthy(); + const response = await createApp(testAppName, request, storageState as StorageState); + expect(response.ok()).toBeTruthy(); }); test.afterAll(async ({ request, testAppName }) => { @@ -84,14 +76,24 @@ test('It is possible to change context and view only Testdepartementet apps', as await dashboardPage.checkThatTTDApplicationsHeaderIsVisible(); }); -test('It is possible to search an app by name', async ({ page, testAppName }) => { +test('It is possible to search an app by name', async ({ + page, + testAppName, + request, + storageState, +}) => { const dashboardPage = await setupAndVerifyDashboardPage(page, testAppName); - const testAppName2 = `${testAppName}2`; + const testAppName2 = getExtraAppName(testAppName); + + // Need to wait a bit to make sure that Gitea does not crash + dashboardPage.waitForXAmountOfMilliseconds(3000); + const response = await createApp(testAppName2, request, storageState as StorageState); + expect(response.ok()).toBeTruthy(); await dashboardPage.checkThatAppIsVisible(testAppName); await dashboardPage.checkThatAppIsVisible(testAppName2); - await dashboardPage.typeInSearchField('2'); + await dashboardPage.typeInSearchField('extra'); await dashboardPage.checkThatAppIsHidden(testAppName); await dashboardPage.checkThatAppIsVisible(testAppName2); }); diff --git a/frontend/testing/playwright/tests/logout-and-invalid-login-only/logout-and-invalid-login-only.spec.ts b/frontend/testing/playwright/tests/logout-and-invalid-login-only/logout-and-invalid-login-only.spec.ts index 4d37fdccb87..d886f20d4ba 100644 --- a/frontend/testing/playwright/tests/logout-and-invalid-login-only/logout-and-invalid-login-only.spec.ts +++ b/frontend/testing/playwright/tests/logout-and-invalid-login-only/logout-and-invalid-login-only.spec.ts @@ -1,6 +1,8 @@ import { test } from '../../extenders/testExtend'; import { LoginPage } from '../../pages/LoginPage'; import { DashboardPage } from '../../pages/DashboardPage'; +import { expect } from '@playwright/test'; +import { Language } from '../../enum/Language'; // This line must be there to ensure that the tests do not run in parallell, and // that the before all call is being executed before we start the tests @@ -32,6 +34,21 @@ test('That it is not possible to login with invalid credentials', async ({ await loginPage.goToAltinnLoginPage(); await loginPage.goToGiteaLoginPage(); + const lang = await loginPage.getLanguage(); + + if (lang !== Language.Norwegian) { + await loginPage.clickOnLanguageMenu(); + await loginPage.clickOnNorwegianLanguageOption(); + + // Changing langauge happens too fast in the browser, so we need to add some waiting + await loginPage.waitForXAmountOfMilliseconds(2000); + + const langAfterchange = await loginPage.getLanguage(); + expect(langAfterchange).toBe(Language.Norwegian); + } else { + expect(lang).toBe(Language.Norwegian); + } + await loginPage.writeUsername(process.env.PLAYWRIGHT_USER); await loginPage.writePassword('123'); diff --git a/frontend/testing/playwright/tests/main-navigation-between-sub-apps/main-navigation-between-sub-apps.spec.ts b/frontend/testing/playwright/tests/main-navigation-between-sub-apps/main-navigation-between-sub-apps.spec.ts index 19c3560a772..07d74b29116 100644 --- a/frontend/testing/playwright/tests/main-navigation-between-sub-apps/main-navigation-between-sub-apps.spec.ts +++ b/frontend/testing/playwright/tests/main-navigation-between-sub-apps/main-navigation-between-sub-apps.spec.ts @@ -14,6 +14,8 @@ import { DeployPage } from '../../pages/DeployPage'; import { Header } from '../../components/Header'; import { Gitea } from '../../helpers/Gitea'; +const getTtdApp = (appName: string) => `ttd-app-${appName}`; + // Before the tests starts, we need to create the dashboard app test.beforeAll(async ({ testAppName, request, storageState }) => { // Create a new app @@ -28,7 +30,7 @@ test.afterAll(async ({ request, testAppName }) => { expect(response.ok()).toBeTruthy(); const responseTTD = await request.delete( - gitea.getDeleteAppEndpoint({ org: 'ttd', app: testAppName }), + gitea.getDeleteAppEndpoint({ org: 'ttd', app: getTtdApp(testAppName) }), ); expect(responseTTD.ok()).toBeTruthy(); }); @@ -138,8 +140,9 @@ test('That it is possible to navigate from overview to the deploy page and back storageState, }) => { const testDepartmentOrg: string = 'ttd'; + const appName: string = getTtdApp(testAppName); // Need a different app name than the one generated by the user in beforeAll() - const designerApi = new DesignerApi({ app: testAppName }); + const designerApi = new DesignerApi({ app: appName }); const response = await designerApi.createApp( request, storageState as StorageState, @@ -147,10 +150,10 @@ test('That it is possible to navigate from overview to the deploy page and back ); expect(response.ok()).toBeTruthy(); - const dashboardPage = new DashboardPage(page, { app: testAppName }); - const overviewPage = new OverviewPage(page, { app: testAppName }); - const deployPage = new DeployPage(page, { app: testAppName }); - const header = new Header(page, { app: testAppName }); + const dashboardPage = new DashboardPage(page, { app: appName }); + const overviewPage = new OverviewPage(page, { app: appName }); + const deployPage = new DeployPage(page, { app: appName }); + const header = new Header(page, { app: appName }); await dashboardPage.loadDashboardPage(); await dashboardPage.verifyDashboardPage(); @@ -161,13 +164,18 @@ test('That it is possible to navigate from overview to the deploy page and back await dashboardPage.checkThatTTDApplicationsHeaderIsVisible(); expect(dashboardPage.org).toEqual('ttd'); - await dashboardPage.clickOnTestAppEditButton(testAppName); + + await dashboardPage.typeInSearchField(appName); + await dashboardPage.checkThatAppIsVisible(appName); + await dashboardPage.clickOnTestAppEditButton(appName); // As we have changed env.org to 'ttd', we need to update the org of the new classes to make sure it works. overviewPage.updateOrgNameEnv(testDepartmentOrg); deployPage.updateOrgNameEnv(testDepartmentOrg); header.updateOrgNameEnv(testDepartmentOrg); + // overviewPage.waitForXAmountOfMilliseconds(3000); + await overviewPage.verifyOverviewPage(); // Check Navigation diff --git a/frontend/testing/playwright/tests/settings-modal/settings-modal.spec.ts b/frontend/testing/playwright/tests/settings-modal/settings-modal.spec.ts index 8de1ea92d37..4109369c628 100644 --- a/frontend/testing/playwright/tests/settings-modal/settings-modal.spec.ts +++ b/frontend/testing/playwright/tests/settings-modal/settings-modal.spec.ts @@ -101,6 +101,9 @@ test('That it is possible to edit security level on "Policy editor" tab, and tha const securityValueAfterChange = await policyEditor.getSelectedSecurityLevel(); expect(securityValueAfterChange).toBe(securityLevel3Text); + // In dev, the API call to save the policy takes some time, and therefore we add functionality to wait for a while to wait for the save to happen + await settingsModal.waitForXAmountOfMilliseconds(4000); + await settingsModal.navigateToTab('about'); await settingsModal.verifyThatTabIsVisible('about'); await settingsModal.verifyThatTabIsHidden('policy');