Skip to content
Draft
Show file tree
Hide file tree
Changes from all 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
18 changes: 17 additions & 1 deletion .github/workflows/dotnet-core-master.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ jobs:
- name: Wait for MariaDB
run: |
for i in {1..30}; do
if docker exec mariadb-test mysql -uroot -psecretpassword -e "SELECT 1" &>/dev/null; then
if docker exec mariadbtest mysql -uroot -psecretpassword -e "SELECT 1" &>/dev/null; then
echo "MariaDB is ready!"
break
fi
Expand Down Expand Up @@ -95,6 +95,22 @@ jobs:
config-file: cypress.config.ts
working-directory: eform-client
command-prefix: "--"
- name: Wait for application to be ready
run: |
echo "Waiting for application at http://localhost:4200 to be ready..."
for i in {1..60}; do
if curl -f -s http://localhost:4200 >/dev/null; then
echo "Application is ready!"
break
fi
echo "Waiting for application... ($i/60)"
sleep 2
done
# Final check
if ! curl -f -s http://localhost:4200 >/dev/null; then
echo "Application failed to start within 120 seconds"
exit 1
fi
- name: testheadless2${{matrix.test}}
run: cd eform-client && npm run testheadless2${{matrix.test}}
- name: Stop the newly build Docker container
Expand Down
18 changes: 17 additions & 1 deletion .github/workflows/dotnet-core-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ jobs:
- name: Wait for MariaDB
run: |
for i in {1..30}; do
if docker exec mariadb-test mysql -uroot -psecretpassword -e "SELECT 1" &>/dev/null; then
if docker exec mariadbtest mysql -uroot -psecretpassword -e "SELECT 1" &>/dev/null; then
echo "MariaDB is ready!"
break
fi
Expand Down Expand Up @@ -96,6 +96,22 @@ jobs:
config-file: cypress.config.ts
working-directory: eform-client
command-prefix: "--"
- name: Wait for application to be ready
run: |
echo "Waiting for application at http://localhost:4200 to be ready..."
for i in {1..60}; do
if curl -f -s http://localhost:4200 >/dev/null; then
echo "Application is ready!"
break
fi
echo "Waiting for application... ($i/60)"
sleep 2
done
# Final check
if ! curl -f -s http://localhost:4200 >/dev/null; then
echo "Application failed to start within 120 seconds"
exit 1
fi
- name: testheadless2${{matrix.test}}
run: cd eform-client && npm run testheadless2${{matrix.test}}
- name: Stop the newly build Docker container
Expand Down
2 changes: 2 additions & 0 deletions eform-client/cypress/e2e/Login.page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ class LoginPage {
loginWithNewPassword() {
this.getUsernameInput().type(loginConstants.username);
this.getPasswordInput().type(loginConstants.newPassword);
cy.intercept('POST', '**/api/templates/index').as('login');
this.getLoginButton().click();
cy.wait('@login', { timeout: 60000 });
cy.get('#newEFormBtn').should('be.visible');
}

Expand Down
3 changes: 2 additions & 1 deletion eform-client/cypress/e2e/Navbar.page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,8 @@ export class Navbar {
this.signOutDropdown().click();
cy.wait(500);
this.logoutBtn().click();
cy.wait(500);
// Wait for login page to be fully loaded
cy.get('#loginBtn', { timeout: 10000 }).should('be.visible');
}

public goToProfileSettings() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,49 +5,41 @@ describe('Password settings - Change password', function () {
before(() => {
cy.visit('http://localhost:4200');
loginPage.login();
passwordSettingsPage.Navbar.goToPasswordSettings();
cy.get('#oldPassword', { timeout: 10000 }).should('be.visible');
});

it('should change password to new password', () => {
cy.wait(500);
it('should change password and revert it back', () => {
// Navigate to password settings
passwordSettingsPage.Navbar.goToPasswordSettings();
cy.get('#oldPassword', { timeout: 10000 }).should('be.visible');

// Change password to new password
// passwordSettingsPage.setNewPassword();
//
// // Logout
// passwordSettingsPage.Navbar.logout();
// cy.get('#loginBtn').should('be.visible');
//
// // Login with new password
// cy.visit('http://localhost:4200');
// loginPage.loginWithNewPassword();
//
// // Verify we're logged in by checking for the new eForm button
// cy.get('#newEFormBtn').should('be.visible');
//
// // Navigate to password settings
// passwordSettingsPage.Navbar.goToPasswordSettings();
// cy.get('#oldPassword').should('be.visible');
});
passwordSettingsPage.setNewPassword();

// Logout (waits for login page to load)
passwordSettingsPage.Navbar.logout();

// Login with new password to verify change worked
cy.visit('http://localhost:4200');
loginPage.loginWithNewPassword();

it('should revert password back to original', () => {
cy.wait(500);
// Verify we're logged in by checking for the new eForm button
cy.get('#newEFormBtn', { timeout: 10000 }).should('be.visible');

// Navigate to password settings to revert
passwordSettingsPage.Navbar.goToPasswordSettings();
cy.get('#oldPassword', { timeout: 10000 }).should('be.visible');

// Revert password back to original
// passwordSettingsPage.revertToOldPassword();
//
// // Logout
// passwordSettingsPage.Navbar.logout();
// cy.get('#loginBtn').should('be.visible');
//
// // Login with original password
// cy.visit('http://localhost:4200');
// loginPage.login();
//
// // Verify we're logged in
// cy.get('#newEFormBtn').should('be.visible');
//
// // Navigate to password settings to verify we can access it
// passwordSettingsPage.Navbar.goToPasswordSettings();
// cy.get('#oldPassword').should('be.visible');
passwordSettingsPage.revertToOldPassword();

// Logout (waits for login page to load)
passwordSettingsPage.Navbar.logout();

// Login with original password to verify revert worked
cy.visit('http://localhost:4200');
loginPage.login();

// Verify we're logged in
cy.get('#newEFormBtn', { timeout: 10000 }).should('be.visible');
});
});
30 changes: 30 additions & 0 deletions eform-client/e2e/Page objects/Login.page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,17 +41,47 @@ class LoginPage extends Page {
}

public async login(): Promise<void> {
console.log('[LOGIN DEBUG] Starting login process...');
console.log('[LOGIN DEBUG] Current URL:', await browser.getUrl());

await (await this.loginBtn()).waitForDisplayed({ timeout: 60000 });
console.log('[LOGIN DEBUG] Login button is displayed');

// await (await this.usernameInput()).waitForDisplayed({ timeout: 60000 });
await (await this.usernameInput()).setValue(LoginConstants.username);
console.log('[LOGIN DEBUG] Username set');

await (await this.passwordInput()).setValue(LoginConstants.password);
console.log('[LOGIN DEBUG] Password set');

await (await this.loginBtn()).click();
console.log('[LOGIN DEBUG] Login button clicked');
console.log('[LOGIN DEBUG] URL after click:', await browser.getUrl());

// Add pause after login click to allow application to start loading on slow environments
await browser.pause(2000);
console.log('[LOGIN DEBUG] Waited 2 seconds, now looking for newEFormBtn...');
console.log('[LOGIN DEBUG] Current URL:', await browser.getUrl());

// Take screenshot before waiting for newEFormBtn to help debug
try {
const screenshotPath = './errorShots/before-newEFormBtn-wait.png';
await browser.saveScreenshot(screenshotPath);
console.log('[LOGIN DEBUG] Screenshot saved to:', screenshotPath);
} catch (e) {
console.log('[LOGIN DEBUG] Could not save screenshot:', e.message);
}

const newEFormBtn = await $('#newEFormBtn');
// Increased timeout for slow environments - application may take longer to initialize
console.log('[LOGIN DEBUG] Waiting for newEFormBtn to be displayed (120s timeout)...');
await newEFormBtn.waitForDisplayed({timeout: 120000});
console.log('[LOGIN DEBUG] newEFormBtn is displayed');

console.log('[LOGIN DEBUG] Waiting for newEFormBtn to be clickable (120s timeout)...');
await newEFormBtn.waitForClickable({timeout: 120000});
console.log('[LOGIN DEBUG] newEFormBtn is clickable - login complete!');
console.log('[LOGIN DEBUG] Final URL:', await browser.getUrl());
}
public async loginWithNewPassword(): Promise<void> {
await (await this.usernameInput()).waitForDisplayed({ timeout: 60000 });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import applicationSettingsPage from '../../Page objects/ApplicationSettings.page
import ApplicationSettingsConstants from '../../Constants/ApplicationSettingsConstants';
import { expect } from 'chai';

describe('Application settings page - site header section', function () {
describe('Application settings page - login page section', function () {
before(async () => {
await loginPage.open('/');
await loginPage.login();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,36 @@ describe('Password settings', function () {
before(async () => {
loginPage.open('/');
loginPage.login();
myEformsPage.Navbar.goToPasswordSettings();
});

it('should set password to 2Times2WillDo', async () => {
it('should change password and revert it back', async () => {
// Navigate to password settings
myEformsPage.Navbar.goToPasswordSettings();

// Change password to new password
passwordSettings.setNewPassword();

// Logout
passwordSettings.Navbar.logout();

// Login with new password to verify change worked
loginPage.open('/');
loginPage.loginWithNewPassword();

// Navigate to password settings to revert
myEformsPage.Navbar.goToPasswordSettings();
// expect(myEformsPage.Navbar.verifyHeaderMenuItem('My eForms')).equal('My eForms');
// expect(myEformsPage.Navbar.verifyHeaderMenuItem('Device Users')).equal('Device Users');
// expect(myEformsPage.Navbar.verifyHeaderMenuItem('Advanced')).equal('Advanced');
});
it('should revert to old password', async () => {

// Revert password back to original
passwordSettings.revertToOldPassword();

// Logout
passwordSettings.Navbar.logout();

// Login with original password to verify revert worked
loginPage.open('/');
loginPage.login();

// Verify we can access password settings again
myEformsPage.Navbar.goToPasswordSettings();
// expect(myEformsPage.Navbar.verifyHeaderMenuItem('Meine eForms')).equal('Meine eForms');
// expect(myEformsPage.Navbar.verifyHeaderMenuItem('Gerätebenutzer')).equal('Gerätebenutzer');
// expect(myEformsPage.Navbar.verifyHeaderMenuItem('Fortgeschritten')).equal('Fortgeschritten');
});
});
80 changes: 70 additions & 10 deletions eform-client/wdio-headless-step2e.conf.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,9 @@ export const config: WebdriverIO.Config = {
// maxInstances can get overwritten per capability. So if you have an in-house Selenium
// grid with only 5 firefox instances available you can make sure that not more than
// 5 instances get started at a time.
maxInstances: 5,
// NOTE: Set to 1 for step2e because these tests modify shared application settings
// and must run sequentially to avoid race conditions
maxInstances: 1,
//
browserName: 'chrome',
'goog:chromeOptions': {
Expand Down Expand Up @@ -176,7 +178,7 @@ export const config: WebdriverIO.Config = {
ui: 'bdd',
//require: 'ts-node/register',
//compilers: ['tsconfig-paths/register'],
timeout: 90000
timeout: 240000
},
//
// =====
Expand Down Expand Up @@ -230,32 +232,90 @@ export const config: WebdriverIO.Config = {
* Function to be executed before a test (in Mocha/Jasmine) or a step (in Cucumber) starts.
* @param {Object} test test details
*/
// beforeTest: function (test) {
// },
beforeTest: async function (test) {
console.log('[DEBUG] Starting test:', test.title);
console.log('[DEBUG] Test file:', test.file);
try {
const url = await browser.getUrl();
console.log('[DEBUG] Initial URL:', url);
} catch (e) {
console.log('[DEBUG] Could not retrieve initial URL:', e.message);
}
},
/**
* Hook that gets executed _before_ a hook within the suite starts (e.g. runs before calling
* beforeEach in Mocha)
*/
// beforeHook: function () {
// },
beforeHook: function (test, context, hookName) {
console.log('[DEBUG] Before hook:', hookName);
if (hookName && hookName.includes('before all')) {
console.log('[DEBUG] This is the "before all" hook - where login happens');
}
},
/**
* Hook that gets executed _after_ a hook within the suite ends (e.g. runs after calling
* afterEach in Mocha)
*/
// afterHook: function () {
// },
afterHook: async function (test, context, { error, result, duration, passed }, hookName) {
if (error) {
console.log('[DEBUG] Hook failed:', hookName);
console.log('[DEBUG] Hook error:', error.message);
console.log('[DEBUG] Hook duration:', duration);

// Take screenshot on hook failure
try {
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
const screenshotPath = `./errorShots/hook-failure-${timestamp}.png`;
await browser.saveScreenshot(screenshotPath);
console.log('[DEBUG] Hook failure screenshot saved to:', screenshotPath);
} catch (e) {
console.log('[DEBUG] Could not save hook failure screenshot:', e.message);
}

// Try to get current URL
try {
const url = await browser.getUrl();
console.log('[DEBUG] URL at hook failure:', url);
} catch (e) {
console.log('[DEBUG] Could not retrieve URL:', e.message);
}
}
},
/**
* Function to be executed after a test (in Mocha/Jasmine) or a step (in Cucumber) ends.
* @param {Object} test test details
*/
afterTest(test, context, { error, result, duration, passed, retries }) {
afterTest: async function (test, context, { error, result, duration, passed, retries }) {
const path = require('path');

// if test passed, ignore, else take and save screenshot.
if (passed) {
return;
}

console.log('[DEBUG] Test failed:', test.title);
console.log('[DEBUG] Error:', error ? error.message : 'No error message');
console.log('[DEBUG] Duration:', duration);

// Capture browser console logs
try {
const logs = await browser.getLogs('browser');
console.log('[DEBUG] Browser console logs:');
logs.forEach(log => {
console.log(` [${log.level}] ${log.message}`);
});
} catch (e) {
console.log('[DEBUG] Could not retrieve browser logs:', e.message);
}

// Capture current URL
try {
const url = await browser.getUrl();
console.log('[DEBUG] Current URL:', url);
} catch (e) {
console.log('[DEBUG] Could not retrieve URL:', e.message);
}

/*
* get the current date and clean it
* const date = (new Date()).toString().replace(/\s/g, '-').replace(/-\(\w+\)/, '');
Expand All @@ -279,7 +339,7 @@ export const config: WebdriverIO.Config = {
const filePath = path.resolve(this.screenshotPath, `${filename}.png`);

console.log('Saving screenshot to:', filePath);
browser.saveScreenshot(filePath);
await browser.saveScreenshot(filePath);
console.log('Saved screenshot to:', filePath);
},
/**
Expand Down
Loading