Skip to content

Commit

Permalink
Feature/e2e playwright systemuser 433 (#442)
Browse files Browse the repository at this point in the history
* running scheduled e2e Playwright tests in AT22 and TT02 (until At23 and 24 is ready)
* Post to Slack when tests fail
  • Loading branch information
Nyeng authored Dec 4, 2024
1 parent 4ae8326 commit f1d003d
Show file tree
Hide file tree
Showing 18 changed files with 496 additions and 20 deletions.
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: [AT22, TT02]
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
165 changes: 165 additions & 0 deletions frontend/playwright/api-requests/ApiRequests.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
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
} 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',
};
}
}
82 changes: 82 additions & 0 deletions frontend/playwright/api-requests/Token.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
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

0 comments on commit f1d003d

Please sign in to comment.