Unverified Commit b48bdf70 authored by Philipp Berger's avatar Philipp Berger
Browse files

chore: release v1.7.0

parent 6d172d1b
# Changelog
### 1.7.0 (2021-08-05)
* **backend:** feat: instrument with metrics
* **health-department:** feat: update route access restrictions for employees
* **health-department:** feat: unified buttons and updated designs
* **locations:** fix: qr code labels and names
* **locations:** feat: inform venue owners about unusally long request times from health departments before sharing data
* **locations:** feat: support special characters in location creation
* **contact-form:** feat: updated string validation
* **webapp:** fix: checkin timer starting time
* **webapp:** fix: timer resets after refresh
* **scanner:** fix: improve camera resolution to scan badges faster
### 1.6.2 (2021-07-29)
* **backend:** ref: split checkin route for scanner and contact-form
......
{
"name": "e2e",
"version": "1.6.2",
"version": "1.7.0",
"main": "index.js",
"private": true,
"engines": {
......
import { login, logout, createGroup, deleteGroup } from '../../locations/helpers/functions';
import { loginHealthDepartment } from '../helper/api/auth.helper';
import { addHealthDepartmentPrivateKeyFile } from '../helper/ui/login.helper';
import { createGroupPayload } from '../../locations/helpers/functions.helper';
const FIRST_GROUP_NAME = 'test group first';
const SECOND_GROUP_NAME = 'second test@group';
const THIRD_GROUP_NAME = 'not matching group';
const GROUPS = [FIRST_GROUP_NAME, SECOND_GROUP_NAME, THIRD_GROUP_NAME];
const MATCHED_GROUPS = [FIRST_GROUP_NAME, SECOND_GROUP_NAME];
const GROUP_IDS = [];
const GROUP_PREFIX = 'group_';
const SEARCH_TERM = 'tes';
describe('Health Department / Group search / Search for a group', () => {
//create groups with different names
before(() => {
login();
GROUPS.forEach(group => {
createGroup({ ...createGroupPayload, name: group });
cy.get('@groupId').then(groupId => {
GROUP_IDS.push(groupId);
});
});
logout();
});
//delete created groups
after(() => {
login();
GROUP_IDS.forEach(id => deleteGroup(id));
});
describe('when searching for groups by name', () => {
it('display groups matching search term', () => {
loginHealthDepartment();
addHealthDepartmentPrivateKeyFile();
cy.getByCy('searchGroup').should('exist').should('be.visible').click();
//search group by term
cy.get('.ant-modal-content').within(($modal) => {
cy.getByCy('groupNameInput').should('exist').should('be.visible').type(SEARCH_TERM);
cy.getByCy('startGroupSearch').should('exist').should('be.visible').click();
//verify 2 groups are found and one is noot
MATCHED_GROUPS.forEach((group) => {
cy.getByCy(GROUP_PREFIX + group).should('exist').should('be.visible');
cy.getByCy(GROUP_PREFIX + group).children().then(($group) => {
expect($group.text()).contains(group);
expect($group.text()).contains(createGroupPayload.streetName + ' ' + createGroupPayload.streetNr + ', ' + createGroupPayload.zipCode + ' ' + createGroupPayload.city);
});
});
cy.getByCy(GROUP_PREFIX + THIRD_GROUP_NAME).should('not.exist');
});
});
});
});
import { login, logout, createGroup, deleteGroup } from '../../locations/helpers/functions';
import { loginHealthDepartment } from '../helper/api/auth.helper';
import { addHealthDepartmentPrivateKeyFile } from '../helper/ui/login.helper';
import { createGroupPayload } from '../../locations/helpers/functions.helper';
const FIRST_GROUP_NAME = 'test group first';
const SECOND_GROUP_NAME = 'test group second';
const THIRD_GROUP_NAME = 'not matching group';
const ZIP_CODE_MATCHED = '12345';
const ZIP_CODE_MISMATCHED = '54321';
const GROUP_ZIP_MAP = { [FIRST_GROUP_NAME]: ZIP_CODE_MATCHED, [SECOND_GROUP_NAME]: ZIP_CODE_MISMATCHED, [THIRD_GROUP_NAME]: ZIP_CODE_MATCHED };
const GROUP_IDS = [];
const GROUP_PREFIX = 'group_';
const SEARCH_TERM = 'tes';
describe('Health Department / Group search / Search for a group by Name and Zip code', () => {
//create groups with different names and zip codes
before(() => {
login();
for (const [key, value] of Object.entries(GROUP_ZIP_MAP)) {
createGroup({ ...createGroupPayload, name: key, zipCode: value });
cy.get('@groupId').then(groupId => {
GROUP_IDS.push(groupId);
});
};
logout();
});
beforeEach(() => {
loginHealthDepartment();
addHealthDepartmentPrivateKeyFile();
});
//delete created groups
after(() => {
login();
GROUP_IDS.forEach(id => deleteGroup(id));
});
describe('when searching for groups by zip code', () => {
it('disables the search button', () => {
cy.getByCy('searchGroup').should('exist').should('be.visible').click();
//search group by term
cy.get('.ant-modal-content').within(($modal) => {
cy.get('#zipCode').should('exist').should('be.visible').type(ZIP_CODE_MATCHED);
cy.getByCy('startGroupSearch').should('exist').should('be.disabled');
});
});
});
describe('when searching for a groups by Name and Zip code', () => {
it('displays groups matching search criteria', () => {
cy.getByCy('searchGroup').should('exist').should('be.visible').click();
//search groups by name and zip
cy.get('.ant-modal-content').within(($modal) => {
cy.getByCy('groupNameInput').should('exist').should('be.visible').type(SEARCH_TERM);
cy.get('#zipCode').should('exist').should('be.visible').type(ZIP_CODE_MATCHED);
cy.getByCy('startGroupSearch').should('exist').should('be.visible').click();
//verify one group matching name and zip is found
cy.getByCy(GROUP_PREFIX + FIRST_GROUP_NAME).should('exist').should('be.visible');
cy.getByCy(GROUP_PREFIX + FIRST_GROUP_NAME).children().then(($group) => {
expect($group.text()).contains(FIRST_GROUP_NAME);
expect($group.text()).contains(`${createGroupPayload.streetName} ${createGroupPayload.streetNr}, ${ZIP_CODE_MATCHED} ${createGroupPayload.city}`);
});
//verify groups with different name or zip are not found
cy.getByCy(GROUP_PREFIX + SECOND_GROUP_NAME).should('not.exist');
cy.getByCy(GROUP_PREFIX + THIRD_GROUP_NAME).should('not.exist');
});
});
});
});
\ No newline at end of file
export const HEALTH_DEPARTMENT_BASE_ROUTE = '/health-department';
export const HEALTH_DEPARTMENT_APP_ROUTE = `${HEALTH_DEPARTMENT_BASE_ROUTE}/app`;
export const HEALTH_DEPARTMENT_TRACKING_ROUTE = '/app/tracking';
export const HEALTH_DEPARTMENT_USER_MANAGEMENT_ROUTE = `${HEALTH_DEPARTMENT_BASE_ROUTE}/app/user-management`;
......@@ -41,11 +41,7 @@ export const uploadHealthDepartmentPrivateKeyFile = () => {
};
export const removeHealthDepartmentPrivateKeyFile = () => {
cy.task('fileExists', HEALTH_DEPARTMENT_PRIVATE_KEY_PATH).then(exists => {
if (exists) {
cy.exec(`rm ${HEALTH_DEPARTMENT_PRIVATE_KEY_PATH}`);
}
});
cy.task('deleteFileIfExists', HEALTH_DEPARTMENT_PRIVATE_KEY_PATH);
};
export const addHealthDepartmentPrivateKeyFile = () => {
......
export const setDatePickerTime = () => {
cy.get('.ant-picker-dropdown').not('.ant-picker-dropdown-hidden').should('exist').within(() => {
cy.get('.ant-picker-time-panel-cell').eq(0).click().type('{enter}');
});
};
export const setDatePickerStartDate = (startDate) => {
cy.get('#startDate').should('exist').should('be.visible').click().type(`${startDate}{enter}`);
cy.get('#startTime').should('exist').should('be.visible').click();
setDatePickerTime();
};
export const setDatePickerEndDate = (endDate) => {
cy.get('#endDate').should('exist').click({ force: true }).type(`${endDate}{enter}`);
cy.get('#endTime').should('exist').click();
setDatePickerTime();
};
\ No newline at end of file
import moment from 'moment';
import { loginHealthDepartment } from '../../helper/api/auth.helper';
import { addHealthDepartmentPrivateKeyFile } from '../../helper/ui/login.helper';
import { setDatePickerStartDate, setDatePickerEndDate } from '../../helper/ui/tracking.helper';
import { E2E_DEFAULT_GROUP_NAME } from '../../../locations/helpers/locations.js';
const GROUP_PREFIX = 'group_';
const YESTERDAY = moment().subtract(1, 'days').format('DD.MM.YYYY');
const TODAY = moment().format('DD.MM.YYYY');
describe('Health Department / Tracking / Location tracking', () => {
describe('when close tracking process', () => {
it('the process disappears from the list', () => {
loginHealthDepartment();
addHealthDepartmentPrivateKeyFile();
//search E2E group
cy.getByCy('searchGroup').should('exist').should('be.visible').click();
cy.getByCy('groupNameInput').should('exist').should('be.visible').type(E2E_DEFAULT_GROUP_NAME);
cy.getByCy('startGroupSearch').should('exist').should('be.visible').click();
cy.getByCy(GROUP_PREFIX + E2E_DEFAULT_GROUP_NAME).should('exist').should('be.visible').click();
//set tracking dates
setDatePickerStartDate(YESTERDAY);
setDatePickerEndDate(TODAY);
//open tracking process
cy.getByCy('requestGroupData').click();
cy.getByCy('processEntry').should('contain', E2E_DEFAULT_GROUP_NAME).first().click();
//close tracking process
cy.getByCy('complete').should('exist').click();
cy.get('.ant-popover-inner-content').within(($popup) => {
cy.get('.ant-btn-primary').should('exist').click();
});
//verify process is not in the list
cy.getByCy('emptyProcesses').should('exist').should('be.visible');
});
});
});
import faker from 'faker';
import { loginHealthDepartment, logout } from '../helper/api/auth.helper';
import { loginToHD, openHDLoginPage, addHealthDepartmentPrivateKeyFile } from '../helper/ui/login.helper';
import { HEALTH_DEPARTMENT_TRACKING_ROUTE, HEALTH_DEPARTMENT_USER_MANAGEMENT_ROUTE } from '../helper/routes';
const EMPLOYEE_FIRST_NAME = faker.name.firstName();
const EMPLOYEE_LAST_NAME = faker.name.lastName();
const EMPLOYEE_PHONE = faker.phone.phoneNumber('170 #######');
const EMPLOYEE_EMAIL = 'employee@hd.com';
describe('Health Department / User Management / Create new employee', () => {
describe('when create a new HD employee', () => {
it('the employee is created and able to login', () => {
loginHealthDepartment();
cy.visit(HEALTH_DEPARTMENT_USER_MANAGEMENT_ROUTE);
cy.getByCy('addEmployee').should('exist').should('be.visible').click();
//fillin employee form
cy.get('.ant-modal').within(($modal) => {
cy.get('#firstName').should('exist').should('be.visible').type(EMPLOYEE_FIRST_NAME);
cy.get('#lastName').should('exist').should('be.visible').type(EMPLOYEE_LAST_NAME);
cy.get('#phone').should('exist').should('be.visible').type(EMPLOYEE_PHONE);
cy.get('#email').should('exist').should('be.visible').type(EMPLOYEE_EMAIL);
cy.get('button[type=button]').should('exist').should('be.visible');
cy.get('button[type=submit]').should('exist').should('be.visible').click();
});
//save generated password
cy.get('.ant-notification').should('exist').should('be.visible');
cy.get('.ant-modal').within(($modal) => {
cy.getByCy('generatedPassword').then(($password) => {
cy.wrap($password.text()).as('password');
});
cy.get('button[type=button]').should('exist').should('be.visible').click();
});
cy.get('.ant-popconfirm').within(($popup) => {
cy.get('.ant-popover-buttons > button:nth-child(1)').should('exist').should('be.visible');
cy.get('.ant-popover-buttons > .ant-btn-primary').should('exist').should('be.visible').click();
});
//verify employee is created
cy.get('#employeeTable > div').last().then(($row) => {
expect($row.text()).contains(EMPLOYEE_FIRST_NAME + ' ' + EMPLOYEE_LAST_NAME);
expect($row.text()).contains(EMPLOYEE_PHONE);
expect($row.text()).contains(EMPLOYEE_EMAIL);
});
logout();
//login as a new employee
openHDLoginPage();
cy.get('@password').then(password => {
loginToHD(EMPLOYEE_EMAIL, password);
})
cy.url().should('include', HEALTH_DEPARTMENT_TRACKING_ROUTE);
});
});
});
......@@ -6,16 +6,15 @@ import {
deleteGroup,
} from '../helpers/functions';
import {
DEVICE_TYPES,
traceDataPayload,
createGroupPayload,
DEVICE_TYPES,
} from '../helpers/functions.helper';
import { DELETE_E2E_TRACE_QUERY } from '../helpers/dbQueries.js';
import {
verifyLocationOverview,
verifyScannerCounter,
verifyLocationOverview,
} from '../helpers/inputValidation.helper';
import { E2E_DEFAULT_LOCATION_FORM } from '../helpers/locations';
const CHECKIN_GROUP_NAME = 'neXenio';
......
......@@ -15,7 +15,6 @@ import {
createGroup,
deleteGroup,
} from '../helpers/functions';
import { E2E_DEFAULT_LOCATION_FORM } from '../helpers/locations';
const CHECKIN_GROUP_NAME = 'neXenio';
......
......@@ -32,9 +32,11 @@ describe('Download QR Codes PDF', () => {
cy.getByCy('yes').click();
cy.getByCy('download').click();
cy.get('.ant-message-notice').should('exist');
cy.get('.ant-message-notice').should('not.exist');
cy.readFile('./downloads/luca_QRCode_Test Restaurant_General.pdf');
cy.exec('rm ./downloads/luca_QRCode_Test\\ Restaurant_General.pdf');
cy.get('.ant-message-notice', { timeout: 20000 }).should('not.exist');
cy.readFile(
'./downloads/luca_QRCode_Test Restaurant_Test Restaurant.pdf'
);
cy.task('deleteFileIfExists', './downloads/luca_QRCode_Test Restaurant_Test Restaurant.pdf');
});
});
......@@ -55,18 +57,16 @@ describe('Download QR Codes PDF', () => {
cy.getByCy('done').click();
cy.getByCy('yes').click();
cy.getByCy('qrCodeDownload').click();
cy.get('.ant-message-notice').should('not.exist');
cy.get('.ant-message-notice', { timeout: 20000 }).should('not.exist');
cy.readFile(
'./downloads/luca_QRCode_Nexenio_1 e2e_NEW_RESTAURANT_LOCATION.pdf'
);
cy.exec(
'rm ./downloads/luca_QRCode_Nexenio_1\\ e2e_NEW_RESTAURANT_LOCATION.pdf'
'./downloads/luca_QRCode_Nexenio_1 e2e_Nexenio_1 e2e - NEW_RESTAURANT_LOCATION.pdf'
);
cy.task('deleteFileIfExists', './downloads/luca_QRCode_Nexenio_1 e2e_Nexenio_1 e2e - NEW_RESTAURANT_LOCATION.pdf');
});
});
describe('On Location page', () => {
it('downloads the Tables PDF', () => {
it('downloads the Tables PDF', { retries: 2 }, () => {
cy.getByCy('location-NEW_RESTAURANT_LOCATION').click();
cy.getByCy('locationCard-tableSubdivision').click();
cy.getByCy('activateTableSubdivision').click();
......@@ -74,11 +74,9 @@ describe('Download QR Codes PDF', () => {
cy.getByCy('qrCodeDownload').click();
cy.get('.ant-message-notice', { timeout: 40000 }).should('not.exist');
cy.readFile(
'./downloads/luca_QRCodes_Nexenio_1 e2e_NEW_RESTAURANT_LOCATION_Tables.pdf'
);
cy.exec(
'rm ./downloads/luca_QRCodes_Nexenio_1\\ e2e_NEW_RESTAURANT_LOCATION_Tables.pdf'
'./downloads/luca_QRCodes_Nexenio_1 e2e_Nexenio_1 e2e - NEW_RESTAURANT_LOCATION_Tables.pdf'
);
cy.task('deleteFileIfExists', './downloads/luca_QRCodes_Nexenio_1 e2e_Nexenio_1 e2e - NEW_RESTAURANT_LOCATION_Tables.pdf');
});
it('downloads the Location PDF if tables are configured', () => {
......@@ -94,12 +92,10 @@ describe('Download QR Codes PDF', () => {
cy.getByCy('qrCodeDownload').click();
cy.get('.ant-message-notice', { timeout: 20000 }).should('not.exist');
cy.readFile(
'./downloads/luca_QRCode_Nexenio_1 e2e_NEW_RESTAURANT_LOCATION.pdf',
'./downloads/luca_QRCode_Nexenio_1 e2e_Nexenio_1 e2e - NEW_RESTAURANT_LOCATION.pdf',
{ timeout: 20000 }
);
cy.exec(
'rm ./downloads/luca_QRCode_Nexenio_1\\ e2e_NEW_RESTAURANT_LOCATION.pdf'
);
cy.task('deleteFileIfExists', './downloads/luca_QRCode_Nexenio_1 e2e_Nexenio_1 e2e - NEW_RESTAURANT_LOCATION.pdf');
});
});
});
......@@ -162,3 +162,9 @@ export const downloadLocationPrivateKeyFile = () => {
cy.getByCy('checkPrivateKeyIsDownloaded').click();
cy.getByCy('finish').should('exist').click();
};
export const checkoutGuests = () => {
cy.getByCy('checkoutGuest').click();
cy.get('.ant-popover-buttons .ant-btn-primary').click();
cy.get('.successCheckout').should('exist');
};
......@@ -3,6 +3,8 @@ import {
E2E_SECOND_LOCATION_NAME,
} from '../helpers/locations';
const TIME_REGEXP = /^\d{2}:\d{2}$/;
export const checkRadiusInput = () => {
// Invalid radius input (empty, under 50 or over 5000):
cy.get('#radius').clear();
......@@ -57,3 +59,26 @@ export const verifyModalWindowIsClosed = () => {
expect($root.find('.ant-modal-content').length).to.equal(0);
});
};
export const verifyGuestsCount = (count) => {
cy.getByCy('guestCount').next().click();
cy.getByCy('guestCount').should('contain', count);
};
export const verifyCheckinGuestTime = (date) => {
cy.get('.ant-modal-content').should('be.visible').within(() => {
cy.getByCy('checkinDate').should('have.text', date);
cy.getByCy('checkinTime').contains(TIME_REGEXP);
cy.getByCy('checkoutDate').should('have.text', '-');
cy.getByCy('checkoutTime').contains('-');
});
};
export const verifyCheckoutGuestTime = (date) => {
cy.get('.ant-modal-content').should('be.visible').within(() => {
cy.getByCy('checkinDate').should('have.text', date);
cy.getByCy('checkinTime').contains(TIME_REGEXP);
cy.getByCy('checkoutDate').should('have.text', date);
cy.getByCy('checkoutTime').contains(TIME_REGEXP);
});
};
import { checkin, login } from '../helpers/functions';
import { traceDataPayload, DEVICE_TYPES } from '../helpers/functions.helper';
import moment from 'moment';
import { DELETE_E2E_TRACE_QUERY } from '../helpers/dbQueries';
import { E2E_DEFAULT_LOCATION_FORM } from '../helpers/locations';
import { checkin, login, checkoutGuests } from '../helpers/functions';
import { traceDataPayload, DEVICE_TYPES } from '../helpers/functions.helper';
import {
verifyCheckinGuestTime,
verifyCheckoutGuestTime,
verifyGuestsCount,
} from '../helpers/inputValidation.helper';
const checkTrackingTime = x => {
const filtered = x.split(' - ').filter(el => el !== '');
return filtered.length;
};
const CURRENT_DATE = moment().format('DD.MM.YYYY');
describe('Locations / Location overview', () => {
before(() => cy.executeQuery(DELETE_E2E_TRACE_QUERY));
beforeEach(() => login());
beforeEach(() => {
cy.executeQuery(DELETE_E2E_TRACE_QUERY);
login();
});
describe('when view new location', () => {
it('no checked-in guests is displayed by default', () => {
cy.getByCy('guestCount').should('contain', 0);
cy.getByCy('showGuestList').click({ force: true });
verifyGuestsCount(0);
cy.getByCy('showGuestList').click();
cy.getByCy('totalCheckinCount').should('contain', 0);
});
});
describe('when check-in/check-out location', () => {
it('guest count and the tracking time is changed', () => {
describe('when check-in/check-out location with contact form', () => {
it('guest count and the tracking time are changed', () => {
// Check in a guest
checkin({ ...traceDataPayload, deviceType: DEVICE_TYPES.mobile });
// Expect the guest count to be 1
cy.getByCy('guestCount').next().should('be.visible').click();
cy.getByCy('guestCount').should('contain', 1);
verifyGuestsCount(1);
// Expect the total checkin count to be 1 within the guest list modal
cy.getByCy('showGuestList').click({ force: true });
cy.getByCy('totalCheckinCount').contains(1);
cy.getByCy('trackingTime').then(el => {
expect(checkTrackingTime(el.text())).to.equal(1);
});
cy.getByCy('showGuestList').click();
cy.getByCy('totalCheckinCount').should('exist').and('contain', 1);
verifyCheckinGuestTime(CURRENT_DATE);
cy.get('.ant-modal-close-x').click();
// Check out the guest
cy.getByCy('checkoutGuest').click();
cy.get('.ant-popover-buttons .ant-btn-primary').click();
cy.get('.successCheckout').should('exist');
checkoutGuests();
// Expect the total checkin count to be 1 in the guest list modal
cy.getByCy('showGuestList').click({ force: true });
cy.getByCy('showGuestList').click();
verifyCheckoutGuestTime(CURRENT_DATE);
});
});
describe('when check-in/check-out location with camera scanner', () => {
it('guest count and the tracking time are changed', () => {
// Check in a guest
checkin({ ...traceDataPayload, deviceType: DEVICE_TYPES.mobile });
// Expect the guest count to be 1
verifyGuestsCount(1);
// Expect the total checkin count to be 1 within the guest list modal
cy.getByCy('showGuestList').click();
cy.getByCy('totalCheckinCount').should('exist').and('contain', 1);
// Expect the both checkin and checkout time exist in the guest list modal
cy.getByCy('showGuestList').click({ force: true });
cy.getByCy('trackingTime').then(el => {
setTimeout(
() => expect(checkTrackingTime(el.text())).to.equal(2),
3000
);
});
verifyCheckinGuestTime(CURRENT_DATE);
cy.get('.ant-modal-close-x').click();
// Check out the guest
checkoutGuests();
// Expect the total checkin count to be 1 in the guest list modal
cy.getByCy('showGuestList').click();
verifyCheckoutGuestTime(CURRENT_DATE);
});
});
});
import {createGroupPayload} from "../../locations/helpers/functions.helper";
import {basicLocationLogin, createGroup, deleteGroup, logout} from "../../locations/helpers/functions";
import {clearDatabase} from "../helpers/database";
import {registerDevice} from "../helpers/functions";
import {clean} from "../../workflow/helpers/functions";
import { createGroupPayload } from '../../locations/helpers/functions.helper';
import {
addHealthDepartmentPrivateKeyFile,
} from "../../health-department/helper/ui/login.helper";
import {loginHealthDepartment} from "../../health-department/helper/api/auth.helper";
import {WEBAPP_ROUTE} from "../helpers/routes";
basicLocationLogin,
createGroup,
deleteGroup,
logout,
} from '../../locations/helpers/functions';
import { clearDatabase } from '../helpers/database';
import { registerDevice } from '../helpers/functions';
import { clean } from '../../workflow/helpers/functions';
import { addHealthDepartmentPrivateKeyFile } from '../../health-department/helper/ui/login.helper';
import { loginHealthDepartment } from '../../health-department/helper/api/auth.helper';
import { WEBAPP_ROUTE, LOCATIONS_ROUTE } from '../helpers/routes';
describe('WebApp / CheckIn', () => {