Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/e2e playwright systemuser 433 #442

Merged
merged 16 commits into from
Dec 4, 2024
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
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
23 changes: 23 additions & 0 deletions .github/workflows/scheduled-playwright.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: Playwright tests (Authentication)

on:
schedule:
# Runs at 7:00 AM UTC every day
- cron: "0 7 * * *"
# Runs at 1:00 PM UTC every day
- cron: "0 13 * * *"

jobs:
playwright-scheduled:
name: "Scheduled Playwright tests"
uses: ./.github/workflows/template-test-playwright.yml
with:
environment: ${{ matrix.environment }}
strategy:
fail-fast: false
matrix:
environment: [TT02]
Nyeng marked this conversation as resolved.
Show resolved Hide resolved
secrets:
USERNAME_TEST_API: ${{ secrets.USERNAME_TEST_API }}
PASSWORD_TEST_API: ${{ secrets.PASSWORD_TEST_API }}
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
18 changes: 18 additions & 0 deletions .github/workflows/template-test-playwright.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ on:
type: string
required: true
description: Environment
secrets:
USERNAME_TEST_API:
required: true
PASSWORD_TEST_API:
required: true
SLACK_WEBHOOK_URL:
required: true

jobs:
playwright:
Expand All @@ -27,6 +34,17 @@ jobs:
- name: Run Playwright tests
working-directory: frontend/playwright
run: yarn run env:${{ inputs.environment }}
env:
USERNAME_TEST_API: ${{ secrets.USERNAME_TEST_API }}
PASSWORD_TEST_API: ${{ secrets.PASSWORD_TEST_API }}
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}

- name: Notify Slack on Failure
if: failure() # This step runs only if the previous steps fail
run: |
curl -X POST -H 'Content-type: application/json' --data '{
"text": ":playwright: Frontend-tester feilet i testmiljø:`${{ inputs.environment }}` på repo: `${{ github.repository }}`. Mer detaljer her: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
}' ${{ secrets.SLACK_WEBHOOK_URL }}
- uses: actions/upload-artifact@v4
if: failure()
with:
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
/frontend/playwright/blob-report/
/frontend/playwright/.cache/
/frontend/playwright/.playwright/
/frontend/playwright/config/.env


# From access management repo:
# Yarn stuff; we're not using PnP/Zero installs
Expand Down
168 changes: 168 additions & 0 deletions frontend/playwright/api-requests/ApiRequests.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
interface PostSystemUserRequestPayload {
systemId: string;
partyOrgNo: string;
externalRef: string;
rights: {
resource: {
id: string;
value: string;
}[];
}[];
redirectUrl: string;
}


export class ApiRequests {


public async cleanUpSystemUsers(systemUsers: { id: string }[], token: string): Promise<void> {
for (const systemuser of systemUsers) {
await this.deleteSystemUser(token, systemuser.id)
}
}

public async getSystemUsers(token: string): Promise<string> {
const endpoint = `v1/systemuser/${process.env.ALTINN_PARTY_ID}`;
const url = `${process.env.API_BASE_URL}${endpoint}`;

try {
const response = await fetch(url, {
method: 'GET',
headers: {
Authorization: `Bearer ${token}`, // Use the token for authentication
'Content-Type': 'application/json',
},
});

if (!response.ok) {
if (response.status === 404) {
console.warn('System users not found (404).');
return '[]'; //Return empty list if no users to be deleted
}
const errorText = await response.text();
console.error('Failed to fetch system users:', response.status, errorText);
console.log(response.status)
throw new Error(`Failed to fetch system users: ${response.statusText}`);
}

const data = await response.json(); // Assuming the API returns JSON data
return JSON.stringify(data, null, 2); // Format the JSON for better readability (optional)
} catch (error) {
console.error('Error fetching system users:', error);
throw new Error('Error fetching system users. Check logs for details.');
}

}

public async deleteSystemUser(token: string, systemUserId: string): Promise<void>{
const endpoint = `v1/systemuser/${process.env.ALTINN_PARTY_ID}/${systemUserId}`
const url = `${process.env.API_BASE_URL}${endpoint}`

try {
const response = await fetch(url, {
method: 'DELETE',
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
});

if (!response.ok) {
const errorBody = await response.text(); // Read the error body if needed
console.error('Failed to delete system user:', response.status, errorBody);
throw new Error(`Failed to delete system user: ${response.statusText}`);
}
} catch (error) {
console.error('Error during system user deletion:', error);
throw new Error('System user deletion failed. Check logs for details.');
}
}


public async sendPostRequest<T>(payload: PostSystemUserRequestPayload, endpoint: string, token: string): Promise<T> {
const url = `${process.env.API_BASE_URL}${endpoint}`

try {
const response = await fetch(url, {
method: 'POST',
headers: {
'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 data = await response.json();
return data as Promise<T>; // Return the response data
Nyeng marked this conversation as resolved.
Show resolved Hide resolved
} catch (error) {
console.error('Error:', error);
throw error; // Rethrow the error to handle it in the test
}
}

/**
* 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<T>(endpoint: string, token: string): Promise<T> {
const url = `${process.env.API_BASE_URL}${endpoint}`;

try {
const response = await fetch(url, {
method: 'GET',
headers: {
'Authorization': `Bearer ${token}`, // Add the Authorization header
},
});

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 data = await response.json();
return data; // Return the response data
} catch (error) {
console.error('Error:', error);
throw error; // Rethrow the error to handle it in the test
}
}

generatePayloadSystemUserRequest(): PostSystemUserRequestPayload {
const randomString = Date.now(); // Current timestamp in milliseconds
const randomNum = Math.random().toString(36);
return {
systemId: `${process.env.SYSTEM_ID}`,
partyOrgNo: `${process.env.ORG}`,
externalRef: `${randomNum}${randomString}`,
rights: [
{
resource: [
{
value: "authentication-e2e-test",
id: "urn:altinn:resource"
}
]
},
{
resource: [
{
value: "vegardtestressurs",
id: "urn:altinn:resource"
}
]
}
],
redirectUrl: "https://altinn.no"
};
}

}
83 changes: 83 additions & 0 deletions frontend/playwright/api-requests/Token.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@

export class Token {

private readonly username: string;
private readonly password: string;
private readonly org: string;
private readonly environment: string;

constructor() {
this.username = process.env.USERNAME_TEST_API || '';
this.password = process.env.PASSWORD_TEST_API || '';
this.org = process.env.ORG || '';
this.environment = process.env.environment || '';


if (!this.username || !this.password) {
throw new Error('API username or password is not defined in the environment variables.');
}

if (!this.org || !this.environment) {
throw new Error('ORG or environment is not defined in the environment variables.');
}
}

/**
* Fetches an enterprise Altinn token for a specific organization and environment.
* @param scopes Scopes required for the token.
* @returns The enterprise Altinn token as a string.
*/
public async getEnterpriseAltinnToken(scopes: string): Promise<string> {
// Construct the URL for fetching the enterprise Altinn test token
const url = `https://altinn-testtools-token-generator.azurewebsites.net/api/GetEnterpriseToken` +
`?orgNo=${process.env.ORG}&env=${process.env.environment}&scopes=${scopes}`;

const auth = Buffer.from(`${this.username}:${this.password}`).toString('base64');
const headers = {
'Authorization': `Basic ${auth}`,
};

// Retrieve the token
const token = await this.getAltinnToken(url, headers);
if (!token) {
throw new Error("Token retrieval failed for Enterprise Altinn token");
}

return token;
}

/**
* Used for fetching an Altinn test token for a specific role
* @returns The Altinn test token as a string
*/
public async getPersonalAltinnToken(scopes = ''): Promise<string> {
// Construct the URL for fetching the Altinn test token
const url = `https://altinn-testtools-token-generator.azurewebsites.net/api/GetPersonalToken?env=${process.env.environment}` +
`&pid=${process.env.PID}` +
`&userid=${process.env.ALTINN_USER_ID}` +
`&partyid=${process.env.ALTINN_PARTY_ID}` +
`&authLvl=3&ttl=3000` +
(scopes ? `&scopes=${scopes}` : '');

// Retrieve the token
const auth = Buffer.from(`${this.username}:${this.password}`).toString('base64');
const headers = {
'Authorization': `Basic ${auth}`,
};

const token = await this.getAltinnToken(url, headers);
if (!token) {
throw new Error("Token retrieval failed for Altinn token");
}
return token;
}

private async getAltinnToken(url: string, headers: Record<string, string>): Promise<string> {
const response = await fetch(url, { headers });
if (!response.ok) {
const errorMessage = await response.text(); // Fetch the full error message from the response
throw new Error(`Failed to fetch token: ${response.statusText} - ${errorMessage}`);
}
return response.text();
}
}
8 changes: 8 additions & 0 deletions frontend/playwright/api-requests/global-teardown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { TestdataApi } from "playwright/util/TestdataApi";

async function globalTeardown() {
console.log('Kjører global opprydding...');
await TestdataApi.cleanUpTestUsers();
}

export default globalTeardown;
9 changes: 8 additions & 1 deletion frontend/playwright/config/.env.at22
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
ENV_NAME="at22"
BASE_URL="https://at22.altinn.cloud"
SYSYEMUSER_URL="https://authn.ui.at22.altinn.cloud/authfront/ui/auth/creation"
SYSYEMUSER_URL="https://authn.ui.at22.altinn.cloud/authfront/ui/auth/creation"
API_BASE_URL="https://platform.at22.altinn.cloud/authentication/api/"

ALTINN_PARTY_ID="51359757"
ALTINN_USER_ID="20010849"
PID="14824497789"
ORG="310547891"
SYSTEM_ID="310547891_E2E - Playwright - Authentication"
9 changes: 8 additions & 1 deletion frontend/playwright/config/.env.at23
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
ENV_NAME="at23"
BASE_URL="https://at23.altinn.cloud"
SYSYEMUSER_URL="https://authn.ui.at23.altinn.cloud/authfront/ui/auth/creation"
SYSYEMUSER_URL="https://authn.ui.at23.altinn.cloud/authfront/ui/auth/creation"
API_BASE_URL="https://platform.at23.altinn.cloud/authentication/api/"

ALTINN_PARTY_ID="51359757"
ALTINN_USER_ID="20010849"
PID="14824497789"
ORG="310547891"
SYSTEM_ID="310547891_E2E - Playwright - Authentication"
9 changes: 8 additions & 1 deletion frontend/playwright/config/.env.at24
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
ENV_NAME="at24"
BASE_URL="https://at24.altinn.cloud"
SYSYEMUSER_URL="https://authn.ui.at24.altinn.cloud/authfront/ui/auth/creation"
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"
PID="14824497789"
ORG="310547891"
SYSTEM_ID="310547891_E2E - Playwright - Authentication"
9 changes: 8 additions & 1 deletion frontend/playwright/config/.env.tt02
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
ENV_NAME="tt02"
BASE_URL="https://tt02.altinn.no"
SYSYEMUSER_URL="https://authn.ui.tt02.altinn.no/authfront/ui/auth/creation"
SYSYEMUSER_URL="https://authn.ui.tt02.altinn.no/authfront/ui/auth/creation"
API_BASE_URL="https://platform.tt02.altinn.no/authentication/api/"

ALTINN_PARTY_ID="51573288"
ALTINN_USER_ID="1260880"
PID="14824497789"
ORG="310547891"
SYSTEM_ID="310547891_E2E - Playwright - Authentication"
Loading
Loading