From 236bc963d04f6221ed6727c8fd1cdc81d14466ee Mon Sep 17 00:00:00 2001 From: Martin Gunnerud Date: Fri, 13 Dec 2024 14:06:44 +0100 Subject: [PATCH] Playwright tests for approve and reject change request (#452) * add playwright tests for systemuser change request * refactor * type fix * Update build-deploy-at.yml * fixes * set correct env values in AT24 * remove unused import * check for change request status after approve/reject * Disable deploy and testing in AT24 --- .github/workflows/build-deploy-at.yml | 4 +- .../playwright/api-requests/ApiRequests.tsx | 159 ++++++++++++------ frontend/playwright/config/.env.at24 | 4 +- .../approveSystemUserChangeRequest.spec.ts | 48 ++++++ .../e2eTests/approveSystemUserRequest.spec.ts | 53 ++---- frontend/playwright/util/TestdataApi.tsx | 18 +- 6 files changed, 184 insertions(+), 102 deletions(-) create mode 100644 frontend/playwright/e2eTests/approveSystemUserChangeRequest.spec.ts diff --git a/.github/workflows/build-deploy-at.yml b/.github/workflows/build-deploy-at.yml index 40bfc998..101005aa 100644 --- a/.github/workflows/build-deploy-at.yml +++ b/.github/workflows/build-deploy-at.yml @@ -54,7 +54,7 @@ jobs: strategy: matrix: - environment: [AT22, AT23, AT24] + environment: [AT22] steps: - name: Checkout @@ -80,7 +80,7 @@ jobs: strategy: fail-fast: false matrix: - environment: [AT22, AT23, AT24] + environment: [AT22] uses: "./.github/workflows/template-test-playwright.yml" with: environment: ${{ matrix.environment }} diff --git a/frontend/playwright/api-requests/ApiRequests.tsx b/frontend/playwright/api-requests/ApiRequests.tsx index 237f67ef..0ef1c70d 100644 --- a/frontend/playwright/api-requests/ApiRequests.tsx +++ b/frontend/playwright/api-requests/ApiRequests.tsx @@ -1,3 +1,5 @@ +import { Token } from './Token'; + interface PostSystemUserRequestPayload { systemId: string; partyOrgNo: string; @@ -11,16 +13,37 @@ interface PostSystemUserRequestPayload { redirectUrl: string; } +interface PostSystemUserChangeRequestPayload { + systemId: string; + partyOrgNo: string; + externalRef: string; + requiredRights: { + resource: { + id: string; + value: string; + }[]; + }[]; + redirectUrl: string; +} + export class ApiRequests { - public async cleanUpSystemUsers(systemUsers: { id: string }[], token: string): Promise { + private tokenClass: Token; + + constructor() { + this.tokenClass = new Token(); + } + + public async cleanUpSystemUsers(systemUsers: { id: string }[]): Promise { + const token = await this.tokenClass.getPersonalAltinnToken(); for (const systemuser of systemUsers) { await this.deleteSystemUser(token, systemuser.id); } } - public async getSystemUsers(token: string): Promise { + public async getSystemUsers(): Promise { const endpoint = `v1/systemuser/${process.env.ALTINN_PARTY_ID}`; const url = `${process.env.API_BASE_URL}${endpoint}`; + const token = await this.tokenClass.getPersonalAltinnToken(); try { const response = await fetch(url, { @@ -73,51 +96,95 @@ export class ApiRequests { } } - public async sendPostRequest( - payload: PostSystemUserRequestPayload, - endpoint: string, - token: string, - ): Promise { + public async postSystemuserRequest(externalRef: string) { + const payload = this.generatePayloadSystemUserRequest(externalRef); + const endpoint = 'v1/systemuser/request/vendor'; + const apiResponse = await this.sendPostRequest<{ confirmUrl: string; id: string }>( + payload, + endpoint, + ); + return apiResponse; // Return the Confirmation URL to use in the test + } + + public async approveSystemuserRequest(requestId: string) { + const endpoint = `v1/systemuser/request/${process.env.ALTINN_PARTY_ID}/${requestId}/approve`; const url = `${process.env.API_BASE_URL}${endpoint}`; + const userToken = await this.tokenClass.getPersonalAltinnToken(); try { const response = await fetch(url, { method: 'POST', headers: { + Authorization: `Bearer ${userToken}`, 'Content-Type': 'application/json', - Authorization: `Bearer ${token}`, // Add the Authorization header }, - body: JSON.stringify(payload), }); if (!response.ok) { - const errorBody = await response.text(); // Read the response body - console.error(`HTTP Error! Status: ${response.status}, Response Body: ${errorBody}`); - throw new Error(`HTTP error! Status: ${response.status}, Response Body: ${errorBody}`); + const errorBody = await response.text(); // Read the error body if needed + console.error('Failed to approve system user request:', response.status, errorBody); + throw new Error(`Failed to approve system user request: ${response.statusText}`); } - const data = await response.json(); - return data as Promise; // Return the response data } catch (error) { - console.error('Error:', error); - throw error; // Rethrow the error to handle it in the test + console.error('Error during system user request approval:', error); + throw new Error('System user user request approval. Check logs for details.'); } } - /** - * Sends a GET request to fetch the last system request. - * @param endpoint The API endpoint (relative path). - * @param token The authorization token. - * @returns The response data as JSON. - */ - public async fetchLastSystemRequest(endpoint: string, token: string): Promise { + public async postSystemuserChangeRequest(externalRef: string) { + const payload = this.generatePayloadSystemUserChangeRequest(externalRef); + const endpoint = 'v1/systemuser/changerequest/vendor'; + const apiResponse = await this.sendPostRequest<{ confirmUrl: string }>(payload, endpoint); + return apiResponse.confirmUrl; // Return the Confirmation URL to use in the test + } + + public async getStatusForSystemUserRequest(systemRequestId: string): Promise { + const endpoint = `v1/systemuser/request/vendor/${systemRequestId}`; + return this.sendGetStatusRequest(endpoint); + } + + public async getStatusForSystemUserChangeRequest(systemRequestId: string): Promise { + const endpoint = `v1/systemuser/changerequest/vendor/${systemRequestId}`; + return this.sendGetStatusRequest(endpoint); + } + + private async sendGetStatusRequest(endpoint: string) { + const scopes = + 'altinn:authentication/systemuser.request.read altinn:authentication/systemuser.request.write'; + const token = await this.tokenClass.getEnterpriseAltinnToken(scopes); const url = `${process.env.API_BASE_URL}${endpoint}`; + const response = await fetch(url, { + method: 'GET', + headers: { + Authorization: `Bearer ${token}`, + }, + }); + + if (!response.ok) { + throw new Error(`Failed to fetch status for system user request. Status: ${response.status}`); + } + + const data = await response.json(); + return data; + } + + private async sendPostRequest( + payload: PostSystemUserRequestPayload | PostSystemUserChangeRequestPayload | null, + endpoint: string, + ): Promise { + const url = `${process.env.API_BASE_URL}${endpoint}`; + const scopes = + 'altinn:authentication/systemuser.request.read altinn:authentication/systemuser.request.write'; + const token = await this.tokenClass.getEnterpriseAltinnToken(scopes); try { const response = await fetch(url, { - method: 'GET', + method: 'POST', headers: { + 'Content-Type': 'application/json', Authorization: `Bearer ${token}`, // Add the Authorization header }, + body: JSON.stringify(payload), }); if (!response.ok) { @@ -133,36 +200,11 @@ export class ApiRequests { } } - public async getStatusForSystemUserRequest( - token: string, - systemRequestId: string, - ): Promise { - //Hardcode for now to test: - const endpoint = `v1/systemuser/request/vendor/${systemRequestId}`; - const url = `${process.env.API_BASE_URL}${endpoint}`; - - const response = await fetch(url, { - method: 'GET', - headers: { - Authorization: `Bearer ${token}`, - }, - }); - - if (!response.ok) { - throw new Error(`Failed to fetch status for system user request. Status: ${response.status}`); - } - - const data = await response.json(); - return data; - } - - generatePayloadSystemUserRequest(): PostSystemUserRequestPayload { - const randomString = Date.now(); // Current timestamp in milliseconds - const randomNum = Math.random().toString(36); + private generatePayloadSystemUserRequest(externalRef: string): PostSystemUserRequestPayload { return { systemId: `${process.env.SYSTEM_ID}`, partyOrgNo: `${process.env.ORG}`, - externalRef: `${randomNum}${randomString}`, + externalRef: externalRef, rights: [ { resource: [ @@ -172,6 +214,19 @@ export class ApiRequests { }, ], }, + ], + redirectUrl: 'https://altinn.no', + }; + } + + private generatePayloadSystemUserChangeRequest( + externalRef: string, + ): PostSystemUserChangeRequestPayload { + return { + systemId: `${process.env.SYSTEM_ID}`, + partyOrgNo: `${process.env.ORG}`, + externalRef: externalRef, + requiredRights: [ { resource: [ { @@ -184,4 +239,4 @@ export class ApiRequests { redirectUrl: 'https://altinn.no', }; } -} \ No newline at end of file +} diff --git a/frontend/playwright/config/.env.at24 b/frontend/playwright/config/.env.at24 index 11ea32a6..f9ad22ad 100644 --- a/frontend/playwright/config/.env.at24 +++ b/frontend/playwright/config/.env.at24 @@ -3,8 +3,8 @@ BASE_URL="https://at24.altinn.cloud" SYSYEMUSER_URL="https://authn.ui.at24.altinn.cloud/authfront/ui/auth/creation" API_BASE_URL="https://platform.at24.altinn.cloud/authentication/api/" -ALTINN_PARTY_ID="51359757" -ALTINN_USER_ID="20010849" +ALTINN_PARTY_ID="51321769" +ALTINN_USER_ID="20020071" PID="14824497789" ORG="310547891" SYSTEM_ID="310547891_E2E - Playwright - Authentication" \ No newline at end of file diff --git a/frontend/playwright/e2eTests/approveSystemUserChangeRequest.spec.ts b/frontend/playwright/e2eTests/approveSystemUserChangeRequest.spec.ts new file mode 100644 index 00000000..6ab9db5e --- /dev/null +++ b/frontend/playwright/e2eTests/approveSystemUserChangeRequest.spec.ts @@ -0,0 +1,48 @@ +import test, { expect } from '@playwright/test'; +import { ApiRequests } from '../api-requests/ApiRequests'; +import { TestdataApi } from 'playwright/util/TestdataApi'; + +test.describe('Godkjenn og avvis Systembruker endringsforespørsel', () => { + let api: ApiRequests; + + test.beforeEach(async () => { + api = new ApiRequests(); + }); + + test('Avvis Systembruker endringsforespørsel', async ({ page }): Promise => { + //Generate confirmUrl from API + const externalRef = TestdataApi.generateExternalRef(); + const response = await api.postSystemuserRequest(externalRef); + + await api.approveSystemuserRequest(response.id); + + const confirmUrlChangeRequest = await api.postSystemuserChangeRequest(externalRef); + + await page.goto(confirmUrlChangeRequest); + await page.getByRole('button', { name: 'Avvis' }).click(); + + //Expect user to be logged out + await expect(page).toHaveURL('https://info.altinn.no'); + + //Read from status api to verify that status is not Accepted after clicking "Avvis" + const statusApiRequest = await api.getStatusForSystemUserRequest<{ status: string }>( + response.id, + ); + expect(statusApiRequest.status).toBe('Accepted'); + }); + + test('Godkjenn Systembruker endringsforespørsel', async ({ page }): Promise => { + const externalRef = TestdataApi.generateExternalRef(); + const response = await api.postSystemuserRequest(externalRef); + + await api.approveSystemuserRequest(response.id); + + const confirmUrlChangeRequest = await api.postSystemuserChangeRequest(externalRef); + + await page.goto(confirmUrlChangeRequest); + await page.getByRole('button', { name: 'Godkjenn' }).click(); + + //Expect user to be logged out + await expect(page).toHaveURL('https://info.altinn.no'); + }); +}); diff --git a/frontend/playwright/e2eTests/approveSystemUserRequest.spec.ts b/frontend/playwright/e2eTests/approveSystemUserRequest.spec.ts index c29ad3d4..62d03d91 100644 --- a/frontend/playwright/e2eTests/approveSystemUserRequest.spec.ts +++ b/frontend/playwright/e2eTests/approveSystemUserRequest.spec.ts @@ -1,69 +1,46 @@ import test, { expect } from '@playwright/test'; import { ApiRequests } from '../api-requests/ApiRequests'; -import { Token } from 'playwright/api-requests/Token'; -import { LoginWithUserPage } from 'playwright/pages/loginPage'; +import { TestdataApi } from 'playwright/util/TestdataApi'; test.describe('Godkjenn og avvis Systembrukerforespørsel', () => { - let token: Token; - let loginPage: LoginWithUserPage; let api: ApiRequests; - test.beforeEach(async ({ page }) => { + test.beforeEach(async () => { api = new ApiRequests(); - token = new Token(); - loginPage = new LoginWithUserPage(page); }); test('Avvis Systembrukerforespørsel', async ({ page }): Promise => { //Generate confirmUrl from API - const systemUserRequestResponse = await prepareSystemUserRequest(api, token); + const externalRef = TestdataApi.generateExternalRef(); + const response = await api.postSystemuserRequest(externalRef); - await page.goto(systemUserRequestResponse.confirmUrl); + await page.goto(response.confirmUrl); await page.getByRole('button', { name: 'Avvis' }).click(); //Expect user to be logged out - await expect(loginPage.LOGIN_BUTTON).toBeVisible(); await expect(page).toHaveURL('https://info.altinn.no'); //Read from status api to verify that status is not rejected after clicking "Avvis" - const statusApiRequest = await getStatusForRequestApi(systemUserRequestResponse.id, token); + const statusApiRequest = await api.getStatusForSystemUserRequest<{ status: string }>( + response.id, + ); expect(statusApiRequest.status).toBe('Rejected'); }); test('Godkjenn Systembrukerforespørsel', async ({ page }): Promise => { - const systemUserRequestResponse = await prepareSystemUserRequest(api, token); + const externalRef = TestdataApi.generateExternalRef(); + const response = await api.postSystemuserRequest(externalRef); - await page.goto(systemUserRequestResponse.confirmUrl); + await page.goto(response.confirmUrl); await page.getByRole('button', { name: 'Godkjenn' }).click(); //Expect user to be logged out - await expect(loginPage.LOGIN_BUTTON).toBeVisible(); await expect(page).toHaveURL('https://info.altinn.no'); //Read from status api to verify that status is not Accepted after clicking "Avvis" - const statusApiRequest = await getStatusForRequestApi(systemUserRequestResponse.id, token); + const statusApiRequest = await api.getStatusForSystemUserRequest<{ status: string }>( + response.id, + ); expect(statusApiRequest.status).toBe('Accepted'); }); - - async function prepareSystemUserRequest(api: ApiRequests, tokenclass: Token) { - const payload = api.generatePayloadSystemUserRequest(); - const scopes = - 'altinn:authentication/systemuser.request.read altinn:authentication/systemuser.request.write'; - const token = await tokenclass.getEnterpriseAltinnToken(scopes); - const endpoint = 'v1/systemuser/request/vendor'; - const apiResponse = await api.sendPostRequest<{ confirmUrl: string; id: string }>( - payload, - endpoint, - token, - ); - return { confirmUrl: apiResponse.confirmUrl, id: apiResponse.id }; // Return the Confirmation URL and the ID to use in the test - } - - async function getStatusForRequestApi(id: string, tokenclass: Token) { - const scopes = - 'altinn:authentication/systemuser.request.read altinn:authentication/systemuser.request.write'; - const token = await tokenclass.getEnterpriseAltinnToken(scopes); - const statusResponse = api.getStatusForSystemUserRequest<{ status: string }>(token, id); - return statusResponse; - } -}); \ No newline at end of file +}); diff --git a/frontend/playwright/util/TestdataApi.tsx b/frontend/playwright/util/TestdataApi.tsx index 17c4e905..c5508d18 100644 --- a/frontend/playwright/util/TestdataApi.tsx +++ b/frontend/playwright/util/TestdataApi.tsx @@ -1,23 +1,25 @@ import { ApiRequests } from '../api-requests/ApiRequests'; // Adjust the path based on your project structure -import { Token } from '../api-requests/Token'; // Adjust the path based on your project structure export class TestdataApi { - static async cleanUpTestUsers() { const api = new ApiRequests(); - const tokenclass = new Token(); try { //cleanup method, dont fail test if this fails but log it - const token = await tokenclass.getPersonalAltinnToken(); - const resp = await api.getSystemUsers(token); + const resp = await api.getSystemUsers(); const users = JSON.parse(resp); if (users.length > 0) { - await api.cleanUpSystemUsers(users, token); - } + await api.cleanUpSystemUsers(users); + } } catch (error) { console.error('Error during cleanup:', error); } } -} \ No newline at end of file + + static generateExternalRef() { + const randomString = Date.now(); // Current timestamp in milliseconds + const randomNum = Math.random().toString(36); + return `${randomNum}${randomString}`; + } +}