Skip to content

Commit

Permalink
fix: tests (#87)
Browse files Browse the repository at this point in the history
* fix: tests

Signed-off-by: Mirko Mollik <[email protected]>

* setup deps before run

Signed-off-by: Mirko Mollik <[email protected]>

* fix: tests

Signed-off-by: Mirko Mollik <[email protected]>

---------

Signed-off-by: Mirko Mollik <[email protected]>
  • Loading branch information
cre8 committed Jul 16, 2024
1 parent 514361f commit e18c620
Show file tree
Hide file tree
Showing 20 changed files with 201 additions and 125 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ jobs:
run: echo "127.0.0.1 host.testcontainers.internal" | sudo tee -a /etc/hosts

- name: Lint, test, build, e2e
run: INPUT_GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }} pnpm exec nx affected -t lint test e2e-ci
run: INPUT_GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }} pnpm exec nx affected -t lint test container e2e
# comment out since the current e2e tests do not produce any artifacts
# - name: Upload coverage
# uses: codecov/codecov-action@v4
Expand Down
61 changes: 61 additions & 0 deletions apps/holder-app-e2e/global-setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import {
Keycloak,
HolderBackend,
HolderFrontend,
IssuerBackend,
VerifierBackend,
} from '@credhub/testing';
import { appendFileSync } from 'fs';

export interface GlobalConfig {
holderFrontendPort: number;
keycloakPort: number;
verifierPort: number;
issuerPort: number;
}

export const CONFIG_KEY = 'CONFIG';

export interface GlobalThisConfig {
config: {
keycloak: Keycloak;
holderBackend: HolderBackend;
holderFrontend: HolderFrontend;
issuerBackend: IssuerBackend;
verifierBackend: VerifierBackend;
};
}

export default async function globalSetup() {
if (process.env['NO_CONTAINER']) {
process.env[CONFIG_KEY] = JSON.stringify({
holderFrontendPort: 4200,
keycloakPort: 8080,
verifierPort: 3002,
issuerPort: 3001,
} as GlobalConfig);
}

const keycloak = await Keycloak.init();
const holderBackend = await HolderBackend.init(keycloak);
const holderFrontend = await HolderFrontend.init(holderBackend);
const issuerBackend = await IssuerBackend.init(keycloak);
const verifierBackend = await VerifierBackend.init(keycloak);
const holderFrontendPort = holderFrontend.instance.getMappedPort(80);
const keycloakPort = keycloak.instance.getMappedPort(8080);
const verifierPort = verifierBackend.instance.getMappedPort(3000);
const issuerPort = issuerBackend.instance.getMappedPort(3000);
process.env[CONFIG_KEY] = JSON.stringify({
holderFrontendPort,
keycloakPort,
verifierPort,
issuerPort,
} as GlobalConfig);
(globalThis as unknown as GlobalThisConfig).config = {
keycloak,
holderBackend,
holderFrontend,
issuerBackend,
verifierBackend,
};
}
13 changes: 13 additions & 0 deletions apps/holder-app-e2e/global-teardown.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { GlobalThisConfig } from './global-setup';

export default async function globalTeardown() {
if (process.env['NO_CONTAINER']) {
return;
}
const config = (globalThis as unknown as GlobalThisConfig).config;
await config.keycloak.stop();
await config.holderBackend.stop();
await config.holderFrontend.stop();
await config.issuerBackend.stop();
await config.verifierBackend.stop();
}
18 changes: 5 additions & 13 deletions apps/holder-app-e2e/playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,18 @@ import { config } from 'dotenv';

config();

// For CI, you may want to set BASE_URL to the deployed application.
const baseURL = process.env['BASE_URL'] || 'http://localhost:4200';

/**
* Read environment variables from file.
* https://github.com/motdotla/dotenv
*/

/**
* See https://playwright.dev/docs/test-configuration.
*/
export default defineConfig({
...nxE2EPreset(__filename, { testDir: './src' }),
workers: 1,
//globalSetup: require.resolve('./global-setup'),
//globalTeardown: require.resolve('./global-teardown'),
retries: process.env['CI'] ? 2 : 0,
workers: 2,
timeout: 50000,
globalTimeout: 600000,
globalSetup: require.resolve('./global-setup'),
globalTeardown: require.resolve('./global-teardown'),
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
baseURL,
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: 'on-first-retry',
permissions: ['camera', 'clipboard-read', 'clipboard-write'],
Expand Down
6 changes: 1 addition & 5 deletions apps/holder-app-e2e/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,5 @@
"sourceRoot": "apps/holder-app-e2e/src",
"implicitDependencies": ["holder-app"],
"// targets": "to see all targets run: nx show project holder-app-e2e --web",
"targets": {
"e2e-ci": {
"dependsOn": ["holder-app:container"]
}
}
"targets": {}
}
84 changes: 30 additions & 54 deletions apps/holder-app-e2e/src/credentials.spec.ts
Original file line number Diff line number Diff line change
@@ -1,54 +1,24 @@
import { faker } from '@faker-js/faker';
import { test, expect, Page } from '@playwright/test';
import { register } from './helpers';
import {
Keycloak,
HolderBackend,
HolderFrontend,
IssuerBackend,
VerifierBackend,
} from '@credhub/testing';
import { getConfig, register } from './helpers';
import axios from 'axios';
import { GlobalConfig } from '../global-setup';

export const username = faker.internet.email();
export const password = faker.internet.password();
export let hostname: string;
let keycloak: Keycloak;
let backend: HolderBackend;
let frontend: HolderFrontend;
let issuerBackend: IssuerBackend;
let verifierBackend: VerifierBackend;
let page: Page;
let config: GlobalConfig;

test.beforeAll(async ({ browser }) => {
if (process.env['NO_CONTAINER']) {
hostname = 'http://localhost:4200';
} else {
keycloak = await Keycloak.init();
backend = await HolderBackend.init(keycloak);
frontend = await HolderFrontend.init(backend);
issuerBackend = await IssuerBackend.init(keycloak);
verifierBackend = await VerifierBackend.init(keycloak);
hostname = `http://localhost:${frontend.instance.getMappedPort(80)}`;
}

page = await browser.newPage();
config = getConfig();
hostname = `http://localhost:${config.holderFrontendPort}`;
await register(page, hostname, username, password);
});

test.afterAll(async () => {
if (process.env['NO_CONTAINER']) {
return;
}
await verifierBackend.stop();
await issuerBackend.stop();
await keycloak.stop();
await backend.stop();
await frontend.stop();
});

function getToken() {
const keycloakUrl = 'http://localhost:8080';
const keycloakUrl = `http://localhost:${config.keycloakPort}`;
const realm = 'wallet';
const clientId = 'relying-party';
const clientSecret = 'hA0mbfpKl8wdMrUxr2EjKtL5SGsKFW5D';
Expand All @@ -66,22 +36,18 @@ function getToken() {
}

async function getAxiosInstance(port: number) {
if (process.env['NO_CONTAINER']) {
const token = await getToken();
const host = 'localhost';
return axios.create({
baseURL: `http://${host}:${port}`,
headers: {
Authorization: `Bearer ${token}`,
},
});
} else {
return issuerBackend.getAxiosInstance();
}
const token = await getToken();
const host = 'localhost';
return axios.create({
baseURL: `http://${host}:${port}`,
headers: {
Authorization: `Bearer ${token}`,
},
});
}

async function receiveCredential(pin = false) {
const axios = await getAxiosInstance(3001);
const axios = await getAxiosInstance(config.issuerPort);
const response = await axios.post(`/sessions`, {
credentialSubject: {
prename: 'Max',
Expand All @@ -99,10 +65,15 @@ async function receiveCredential(pin = false) {
const inserButton = await page.waitForSelector('#insert');
await inserButton.click();
if (userPin) {
const el = await page.waitForSelector('#pin-field');
await el.fill(userPin);
await page
.waitForSelector('#pin-field')
.then((element) => element.fill(userPin));
// eslint-disable-next-line playwright/no-wait-for-timeout
await page.waitForTimeout(500);
await page.click('#send');
}
// eslint-disable-next-line playwright/no-wait-for-timeout
await page.waitForTimeout(500);
const acceptButton = await page.waitForSelector('#accept');
await acceptButton.click();
await page.waitForSelector('#credential');
Expand All @@ -123,9 +94,14 @@ test('issuance with pin', async () => {
test('verify credential', async () => {
await receiveCredential();
const credentialId = 'Identity';
const axios = await getAxiosInstance(3002);
const response = await axios.post(`/siop/${credentialId}`);
const uri = response.data.uri;
const axios = await getAxiosInstance(config.verifierPort);
let uri = '';
try {
const response = await axios.post(`/siop/${credentialId}`);
uri = response.data.uri;
} catch (e) {
console.log(e);
}
await page.evaluate(`navigator.clipboard.writeText("${uri}")`);
await page.goto(`${hostname}/scan`);
await page.waitForSelector('#menu').then((menu) => menu.click());
Expand Down
9 changes: 9 additions & 0 deletions apps/holder-app-e2e/src/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
import { Page } from '@playwright/test';
import { CONFIG_KEY, GlobalConfig } from '../global-setup';

export function getConfig() {
const configContent = process.env[CONFIG_KEY];
if (!configContent) {
throw new Error('Config not found');
}
return JSON.parse(configContent) as GlobalConfig;
}

export async function register(
page: Page,
Expand Down
31 changes: 7 additions & 24 deletions apps/holder-app-e2e/src/login.spec.ts
Original file line number Diff line number Diff line change
@@ -1,39 +1,22 @@
import { HolderBackend, HolderFrontend, Keycloak } from '@credhub/testing';
import { test, expect } from '@playwright/test';
import { faker } from '@faker-js/faker';
import { login, logout, register } from './helpers';
import { getConfig, login, logout, register } from './helpers';
import { GlobalConfig } from '../global-setup';

export const username = faker.internet.email();
export const password = faker.internet.password();
export let hostname: string;
let keycloak: Keycloak;
let backend: HolderBackend;
let frontend: HolderFrontend;

test.beforeAll(async ({ browser }) => {
if (process.env['NO_CONTAINER']) {
hostname = 'http://localhost:4200';
} else {
keycloak = await Keycloak.init();
backend = await HolderBackend.init(keycloak);
frontend = await HolderFrontend.init(backend);
hostname = `http://localhost:${frontend.instance.getMappedPort(80)}`;
}
let config: GlobalConfig;
let hostname: string;

test.beforeAll(async ({ browser }) => {
config = getConfig();
const page = await browser.newPage();
hostname = `http://localhost:${config.holderFrontendPort}`;
await register(page, hostname, username, password);
await logout(page, hostname);
});

test.afterAll(async () => {
if (process.env['NO_CONTAINER']) {
return;
}
await keycloak.stop();
await backend.stop();
await frontend.stop();
});

test('register', async ({ page }) => {
const username = faker.internet.email();
const password = faker.internet.password();
Expand Down
1 change: 0 additions & 1 deletion apps/holder-backend-e2e/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
"outputs": ["{workspaceRoot}/coverage/{e2eProjectRoot}"],
"options": {
"jestConfig": "apps/holder-backend-e2e/jest.config.ts",
"passWithNoTests": true,
"runInBand": true
},
"dependsOn": ["holder-backend:container"]
Expand Down
4 changes: 3 additions & 1 deletion apps/holder-backend/package.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
{
"dependencies": {
"@sphereon/pex": "^3.3.3",
"@sphereon/oid4vci-client": "^0.14.0",
"pg": "^8.11.5"
},
"pnpm": {
"patchedDependencies": {
"@sphereon/[email protected]": "patches/@[email protected]"
"@sphereon/[email protected]": "patches/@[email protected]",
"@sphereon/[email protected]": "patches/@[email protected]"
}
}
}
7 changes: 4 additions & 3 deletions apps/issuer-backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@
"sqlite3": "^5.1.7",
"pg": "^8.11.5",
"@sphereon/pex": "^3.3.3",
"@sphereon/oid4vci-issuer": "^0.12.0",
"@sphereon/ssi-express-support": "0.26.0"
"@sphereon/ssi-express-support": "0.26.0",
"@sphereon/oid4vci-issuer": "^0.14.0"
},
"pnpm": {
"patchedDependencies": {
"@sphereon/[email protected]": "patches/@[email protected]",
"@sphereon/[email protected]": "patches/@[email protected]"
"@sphereon/[email protected]": "patches/@[email protected]",
"@sphereon/[email protected]": "patches/@[email protected]"
}
}
}
14 changes: 12 additions & 2 deletions apps/issuer-backend/src/app/issuer/issuer.module.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Module } from '@nestjs/common';
import { Module, OnModuleInit } from '@nestjs/common';
import { IssuerDataService } from './issuer-data.service';
import { IssuerService } from './issuer.service';
import { IssuerController } from './issuer.controller';
Expand All @@ -12,4 +12,14 @@ import { TemplatesModule } from '../templates/templates.module';
controllers: [IssuerController, WellKnownController],
providers: [IssuerService, IssuerDataService],
})
export class IssuerModule {}
export class IssuerModule implements OnModuleInit {
constructor(
private issuerDataService: IssuerDataService,
private issuerService: IssuerService
) {}

async onModuleInit() {
await this.issuerDataService.loadConfig();
await this.issuerService.init();
}
}
Loading

0 comments on commit e18c620

Please sign in to comment.