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

chore: release v1.4.0

parent 843cbaf2
......@@ -10,4 +10,6 @@
*.otf filter=lfs diff=lfs merge=lfs -text
*.ttf filter=lfs diff=lfs merge=lfs -text
*.woff filter=lfs diff=lfs merge=lfs -text
*.woff2 filter=lfs diff=lfs merge=lfs -text
\ No newline at end of file
*.woff2 filter=lfs diff=lfs merge=lfs -text
## documents
*.pdf filter=lfs diff=lfs merge=lfs -text
_
\ No newline at end of file
#!/bin/sh
command -v git-lfs >/dev/null 2>&1 || { echo >&2 "\nThis repository is configured for Git LFS but 'git-lfs' was not found on your path. If you no longer wish to use Git LFS, remove this hook by deleting .git/hooks/post-checkout.\n"; exit 2; }
git lfs post-checkout "$@"
#!/bin/sh
command -v git-lfs >/dev/null 2>&1 || { echo >&2 "\nThis repository is configured for Git LFS but 'git-lfs' was not found on your path. If you no longer wish to use Git LFS, remove this hook by deleting .git/hooks/post-commit.\n"; exit 2; }
git lfs post-commit "$@"
#!/bin/sh
command -v git-lfs >/dev/null 2>&1 || { echo >&2 "\nThis repository is configured for Git LFS but 'git-lfs' was not found on your path. If you no longer wish to use Git LFS, remove this hook by deleting .git/hooks/post-merge.\n"; exit 2; }
git lfs post-merge "$@"
#!/bin/sh
command -v git-lfs >/dev/null 2>&1 || { echo >&2 "\nThis repository is configured for Git LFS but 'git-lfs' was not found on your path. If you no longer wish to use Git LFS, remove this hook by deleting .git/hooks/pre-push.\n"; exit 2; }
git lfs pre-push "$@"
# Changelog
### 1.3.0 (2021-06-18)
### 1.4.0 (2021-06-29)
* **backend:** feat: add test provider key route
* **backend:** feat: add isTrusted to Operators
* **backend:** chore: remove LocationTransferGroups table
* **health-department:** fix: added missing mac check
* **health-department:** fix: session not cleared correctly after automatic checkout due to inactivity
* **health-department:** fix: order of locations changed after contacting venues
* **health-department:** feat: add hover effect to process list for better usability
* **health-department:** feat: new designs for location search
* **health-department:** feat: locations can be search by zip code as additional parameter to the location name
* **health-department:** feat: new designs for profile view
* **health-department:** feat: select profile view got moved from tab to header
* **health-department:** feat: improved locales
* **locations:** fix: session not cleared correctly after automatic checkout due to inactivity
* **locations:** fix: incorrect download file names when downloading qr codes
* **locations:** fix: clear session storage after session timed out
* **locations:** fix: forgot password view displayed a wrong error message if the user is not activated
* **locations:** feat: updated DPA document
* **locations:** feat: updated terms and conditions links for venues
* **locations:** feat: trusted venues can register badges without phone validation
### 1.3.0 (2021-06-20)
* **backend:** feat: improve IP blocks
* **backend:** feat: improve email storage in postgres
* **backend:** feat: updated API documentation
......@@ -11,8 +33,7 @@
* **health-department:** fix: typo in error notification
* **health-department:** fix: status names in process table and filter were not identical
* **health-department:** feat: new designs for process details
* **locations:** fix: input fields for manual input are disab
led under certain conditions
* **locations:** fix: input fields for manual input are disabled under certain conditions
* **locations:** fix: password not persisted after back action in registration
* **locations:** fix: password criterias were not updated after back action in registration
* **locations:** fix: password criterias were not updated after clearing password in registration
......
......@@ -17,4 +17,5 @@ yarn-debug.log*
yarn-error.log*
/downloads/
cypress/screenshots
\ No newline at end of file
cypress/fixtures
cypress/screenshots
const fs = require('fs');
const ffmpeg = require('fluent-ffmpeg');
const path = require('path');
function generateCameraStream(path) {
if (!fs.existsSync('/tmp/luca')) {
......@@ -30,6 +31,12 @@ module.exports = (on, config) => {
await generateCameraStream(path);
return true;
},
deleteFileIfExists: path => {
if (fs.existsSync(path)) {
fs.unlinkSync(path);
}
return true;
}
});
on('before:browser:launch', async (browser = {}, launchOptions) => {
launchOptions.args.push('--another-arg');
......@@ -40,6 +47,9 @@ module.exports = (on, config) => {
launchOptions.args.push(
'--use-file-for-fake-video-capture=/tmp/luca/stream.mjpeg'
);
launchOptions.preferences.default["download"] = {
default_directory: path.join(__dirname, 'downloads'),
};
}
return launchOptions;
......
{
"name": "e2e",
"version": "1.3.0",
"version": "1.4.0",
"main": "index.js",
"private": true,
"engines": {
......
......@@ -6,6 +6,7 @@ import {
E2E_HEALTH_DEPARTMENT_USERNAME,
E2E_HEALTH_DEPARTMENT_PASSWORD,
} from './user';
import path from 'path';
export const loginHealthDepartment = () => {
cy.request({
......@@ -37,7 +38,14 @@ export const logout = () => {
cy.visit(HEALTH_DEPARTMENT_BASE_ROUTE);
};
const deleteHealthDepartmentPrivateKey = () => {
const downloadsFolder = Cypress.config('downloadsFolder');
const keyPath = path.join(downloadsFolder, 'HealthDepartmentKeyFile.luca');
cy.task('deleteFileIfExists', keyPath);
};
export const downloadHealthDepartmentPrivateKey = () => {
deleteHealthDepartmentPrivateKey();
cy.get('.ant-modal').should('exist');
cy.getByCy('downloadPrivateKey', { timeout: 8000 }).click();
cy.getByCy('next').should('exist');
......@@ -45,12 +53,15 @@ export const downloadHealthDepartmentPrivateKey = () => {
cy.getByCy('finish').should('exist');
cy.getByCy('finish').click();
};
export const uploadHealthDepartmentPrivateKeyFile = () => {
cy.get('.ant-modal').should('exist');
cy.readFile('./downloads/HealthDepartmentKeyFile.luca').then(fileContent => {
const downloadsFolder = Cypress.config('downloadsFolder');
const fileName = 'HealthDepartmentKeyFile.luca';
cy.readFile(path.join(downloadsFolder, fileName)).then(fileContent => {
cy.get('input[type="file"]').attachFile({
fileContent,
fileName: 'HealthDepartmentKeyFile.luca',
fileName,
mimeType: 'text/plain',
});
});
......
import { E2E_EMAIL } from '../../helpers/users';
import {
E2E_EMAIL,
E2E_FIRSTNAME,
E2E_LASTNAME,
E2E_PASSWORD,
} from '../../helpers/users';
import { enterEmail } from '../authentication.helper';
const INACTIVE_EMAIL = `inactive-user-${Date.now()}@nexenio.com`;
const NONEXISTENT_EMAIL = 'non-existant-user@nexenio.com';
describe('Forgot password', () => {
beforeEach(() => cy.visit('/'));
it('can sent the reset password email and redirect the user back to the login page', () => {
it('can send the reset password email and redirect the user back to the login page', () => {
enterEmail(E2E_EMAIL);
cy.get('#password').should('exist');
cy.getByCy('forgotPasswordLink').click();
......@@ -15,4 +24,58 @@ describe('Forgot password', () => {
cy.getByCy('loginPage').should('exist');
cy.get('#email').should('exist');
});
it('displays the notification that the account is not activated', () => {
cy.getByCy('loginPage').should('exist');
enterEmail(INACTIVE_EMAIL);
// Register new user
cy.getByCy('confirmRegister').should('exist');
cy.get('#emailDisabled').should('exist');
cy.get('#emailDisabled').should('have.value', INACTIVE_EMAIL);
cy.get('button[type=submit]').should('exist').click();
// Enter new user details
cy.get('#firstName').should('exist').type(E2E_FIRSTNAME);
cy.get('#lastName').should('exist').type(E2E_LASTNAME);
cy.get('button[type=submit]').should('exist').click();
// Enter new user password
cy.getByCy('setPassword').should('exist');
cy.get('#password').should('exist').type(E2E_PASSWORD);
cy.get('#passwordConfirm').should('exist').type(E2E_PASSWORD);
cy.get('button[type=submit]').should('exist').click();
// Accept conditions
cy.getByCy('legalTerms').should('exist');
cy.get('#termsAndConditions').should('exist').click();
cy.get('#avv').should('exist').click();
cy.get('button[type=submit]').should('exist').click();
// Finish registration
cy.getByCy('finishRegister').should('exist');
cy.get('button[type=button]').should('exist').click();
// Return to login form
cy.getByCy('loginPage').should('exist');
enterEmail(INACTIVE_EMAIL);
cy.getByCy('forgotPasswordLink').should('exist').click();
// Send reset link
cy.getByCy('sentResetLinkSubmit').should('exist').click();
// Notification;
cy.get('.ant-notification-notice-icon-warning').should('exist');
});
it('displays the notification that the account does not exist ', () => {
cy.getByCy('loginPage').should('exist');
// Send reset link
cy.visit('/forgotPassword');
enterEmail(NONEXISTENT_EMAIL);
// Notification;
cy.get('.ant-notification-notice-icon-warning').should('exist');
});
});
import {
E2E_DEFAULT_LOCATION_NAME,
E2E_SECOND_LOCATION_NAME,
} from '../helpers/locations';
export const checkRadiusInput = () => {
// Invalid radius input (empty, under 50 or over 5000):
cy.get('#radius').clear();
......@@ -14,3 +19,15 @@ export const checkRadiusInputEdgeCase = () => {
cy.get('#radius').clear().type('testing');
cy.get('.ant-form-item-explain-error').should('exist');
};
export const defaultLocationNameShouldBeRejected = () => {
cy.get('#locationName').type(E2E_DEFAULT_LOCATION_NAME);
cy.getByCy('nextStep').click();
cy.get('.ant-form-item-explain-error').should('exist');
};
export const checkLocationNameIsUnique = () => {
cy.get('#locationName').type(E2E_SECOND_LOCATION_NAME);
cy.getByCy('nextStep').click();
cy.get('.ant-form-item-explain-error').should('exist');
};
......@@ -11,6 +11,9 @@ export const E2E_DEFAULT_LOCATION_NAME = 'General';
export const E2E_SECOND_LOCATION_UUID = 'c951f526-f792-498b-838f-7d1312a792a3';
export const E2E_SECOND_LOCATION_NAME = 'Restaurant';
export const E2E_THIRD_LOCATION_UUID = '04d3e0b3-c64f-43bd-9b1a-f53f9032e312';
export const E2E_THIRD_LOCATION_NAME = 'Nexenio Kitchen';
export const E2E_DEFAULT_LOCATION_SCANNER =
'09eb8d41-1914-4950-9526-36ebc6ad58fd';
export const E2E_DEFAULT_SCANNER_LINK = `https://localhost/scanner/${E2E_DEFAULT_LOCATION_SCANNER}`;
......
......@@ -2,7 +2,7 @@ export const APP_ROUTE = '/app/group';
export const PROFILE_ROUTE = 'app/profile';
export const DATA_TRANSFERS_ROUTE = 'app/dataTransfers';
export const TERMS_CONDITIONS_LINK =
'https://luca-app.de/app-terms-and-conditions/';
'https://www.luca-app.de/operator-terms-and-conditions/';
export const FAQ_LINK = 'https://www.luca-app.de/faq/';
......
export const E2E_EMAIL = 'e2e@nexenio.com';
export const E2E_PASSWORD = 'e2eTesting!';
export const E2E_PHONE_NUMBER = '+49 111 111 11111';
export const E2E_PHONE_NUMBER = '+4917112345678';
export const E2E_FIRSTNAME = 'Torsten';
export const E2E_LASTNAME = 'Tester';
......@@ -6,56 +6,75 @@ import {
NEW_BASE_LOCATION,
BASE_TYPE,
} from '../../helpers/locations';
import { checkRadiusInput } from '../../helpers/inputValidation.helper';
describe('Create base location', () => {
beforeEach(() => login());
afterEach(() => removeLocation(NEW_BASE_LOCATION));
import {
checkRadiusInput,
defaultLocationNameShouldBeRejected,
checkLocationNameIsUnique,
} from '../../helpers/inputValidation.helper';
describe('Without extra information', () => {
it('generate location without auto checkout', () => {
context('Create base location', () => {
describe('Location name validation', () => {
beforeEach(() => login());
it('checks if the location name is the default name', () => {
cy.getByCy(`createLocation-${E2E_DEFAULT_LOCATION_GROUP}`).click();
cy.getByCy(BASE_TYPE).click();
cy.get('#locationName').type(NEW_BASE_LOCATION);
cy.getByCy('nextStep').click();
cy.getByCy('yes').click();
cy.get('#phone').type(E2E_PHONE_NUMBER);
cy.getByCy('nextStep').click();
// Select indoor
cy.getByCy('indoorSelection').click();
cy.getByCy('selectIndoor').click();
cy.get('button[type=submit]').click();
cy.getByCy('no').click();
cy.getByCy('done').click();
cy.getByCy('yes').click();
cy.getByCy('done').click();
cy.getByCy(`location-${NEW_BASE_LOCATION}`);
defaultLocationNameShouldBeRejected();
});
});
describe('With auto checkout', () => {
it('generate new location', () => {
it('checks if the location name is unique', () => {
cy.getByCy(`createLocation-${E2E_DEFAULT_LOCATION_GROUP}`).click();
cy.getByCy(BASE_TYPE).click();
cy.get('#locationName').type(NEW_BASE_LOCATION);
cy.getByCy('nextStep').click();
cy.getByCy('yes').click();
cy.get('#phone').type(E2E_PHONE_NUMBER);
cy.getByCy('nextStep').click();
// Select indoor
cy.getByCy('indoorSelection').click();
cy.getByCy('selectIndoor').click();
cy.get('button[type=submit]').click();
cy.getByCy('yes').click();
// Invalid radius input: empty, under 50 or over 5000
checkRadiusInput();
// Valid radius input
cy.get('#radius').clear().type(100);
cy.getByCy('nextStep').click();
cy.getByCy('done').click();
cy.getByCy('yes').click();
cy.getByCy('done').click();
cy.getByCy(`location-${NEW_BASE_LOCATION}`);
checkLocationNameIsUnique();
});
});
describe('Create a base location', () => {
beforeEach(() => login());
afterEach(() => removeLocation(NEW_BASE_LOCATION));
describe('Without extra information', () => {
it('generate location without auto checkout', () => {
cy.getByCy(`createLocation-${E2E_DEFAULT_LOCATION_GROUP}`).click();
cy.getByCy(BASE_TYPE).click();
cy.get('#locationName').type(NEW_BASE_LOCATION);
cy.getByCy('nextStep').click();
cy.getByCy('yes').click();
cy.get('#phone').type(E2E_PHONE_NUMBER);
cy.getByCy('nextStep').click();
// Select indoor
cy.getByCy('indoorSelection').click();
cy.getByCy('selectIndoor').click();
cy.get('button[type=submit]').click();
cy.getByCy('no').click();
cy.getByCy('done').click();
cy.getByCy('yes').click();
cy.getByCy('done').click();
cy.getByCy(`location-${NEW_BASE_LOCATION}`);
});
});
describe('With auto checkout', () => {
it('generate new location', () => {
cy.getByCy(`createLocation-${E2E_DEFAULT_LOCATION_GROUP}`).click();
cy.getByCy(BASE_TYPE).click();
cy.get('#locationName').type(NEW_BASE_LOCATION);
cy.getByCy('nextStep').click();
cy.getByCy('yes').click();
cy.get('#phone').type(E2E_PHONE_NUMBER);
cy.getByCy('nextStep').click();
// Select indoor
cy.getByCy('indoorSelection').click();
cy.getByCy('selectIndoor').click();
cy.get('button[type=submit]').click();
cy.getByCy('yes').click();
// Invalid radius input: empty, under 50 or over 5000
checkRadiusInput();
// Valid radius input
cy.get('#radius').clear().type(100);
cy.getByCy('nextStep').click();
cy.getByCy('done').click();
cy.getByCy('yes').click();
cy.getByCy('done').click();
cy.getByCy(`location-${NEW_BASE_LOCATION}`);
});
});
});
});
......@@ -7,56 +7,76 @@ import {
NEW_BUILDING_LOCATION,
BUILDING_TYPE,
} from '../../helpers/locations';
import { checkRadiusInput } from '../../helpers/inputValidation.helper';
describe('Create building location', () => {
beforeEach(() => login());
afterEach(() => removeLocation(NEW_BUILDING_LOCATION));
import {
checkRadiusInput,
defaultLocationNameShouldBeRejected,
checkLocationNameIsUnique,
} from '../../helpers/inputValidation.helper';
describe('Without extra information', () => {
it('generate location without auto checkout', () => {
context('Create building location', () => {
describe('Location name validation', () => {
beforeEach(() => login());
it('checks if the location name is the default name', () => {
cy.getByCy(`createLocation-${E2E_DEFAULT_LOCATION_GROUP}`).click();
cy.getByCy(BUILDING_TYPE).click();
cy.get('#locationName').type(NEW_BUILDING_LOCATION);
cy.getByCy('nextStep').click();
cy.getByCy('yes').click();
cy.get('#phone').type(E2E_PHONE_NUMBER);
cy.getByCy('nextStep').click();
// Select indoor
cy.getByCy('indoorSelection').click();
cy.getByCy('selectIndoor').click();
cy.get('button[type=submit]').click();
cy.getByCy('no').click();
cy.getByCy('done').click();
cy.getByCy('yes').click();
cy.getByCy('done').click();
cy.getByCy(`location-${NEW_BUILDING_LOCATION}`);
cy.getByCy(BASE_TYPE).click();
defaultLocationNameShouldBeRejected();
});
});
describe('With auto checkout', () => {
it('generate new location', () => {
it('checks if the location name is unique', () => {
cy.getByCy(`createLocation-${E2E_DEFAULT_LOCATION_GROUP}`).click();
cy.getByCy(BASE_TYPE).click();
cy.get('#locationName').type(NEW_BUILDING_LOCATION);
cy.getByCy('nextStep').click();
cy.getByCy('yes').click();
cy.get('#phone').type(E2E_PHONE_NUMBER);
cy.getByCy('nextStep').click();
// Select indoor
cy.getByCy('indoorSelection').click();
cy.getByCy('selectIndoor').click();
cy.get('button[type=submit]').click();
cy.getByCy('yes').click();
// Invalid radius input: empty, under 50 or over 5000
checkRadiusInput();
// Valid radius input
cy.get('#radius').clear().type(100);
cy.getByCy('nextStep').click();
cy.getByCy('done').click();
cy.getByCy('yes').click();
cy.getByCy('done').click();
cy.getByCy(`location-${NEW_BUILDING_LOCATION}`);
checkLocationNameIsUnique();
});
});
describe('Create a building location', () => {
beforeEach(() => login());
afterEach(() => removeLocation(NEW_BUILDING_LOCATION));
describe('Without extra information', () => {
it('generate location without auto checkout', () => {
cy.getByCy(`createLocation-${E2E_DEFAULT_LOCATION_GROUP}`).click();
cy.getByCy(BUILDING_TYPE).click();
cy.get('#locationName').type(NEW_BUILDING_LOCATION);
cy.getByCy('nextStep').click();
cy.getByCy('yes').click();
cy.get('#phone').type(E2E_PHONE_NUMBER);
cy.getByCy('nextStep').click();
// Select indoor
cy.getByCy('indoorSelection').click();
cy.getByCy('selectIndoor').click();
cy.get('button[type=submit]').click();
cy.getByCy('no').click();
cy.getByCy('done').click();
cy.getByCy('yes').click();
cy.getByCy('done').click();
cy.getByCy(`location-${NEW_BUILDING_LOCATION}`);
});
});
describe('With auto checkout', () => {
it('generate new location', () => {
cy.getByCy(`createLocation-${E2E_DEFAULT_LOCATION_GROUP}`).click();
cy.getByCy(BASE_TYPE).click();
cy.get('#locationName').type(NEW_BUILDING_LOCATION);
cy.getByCy('nextStep').click();
cy.getByCy('yes').click();
cy.get('#phone').type(E2E_PHONE_NUMBER);
cy.getByCy('nextStep').click();
// Select indoor
cy.getByCy('indoorSelection').click();
cy.getByCy('selectIndoor').click();
cy.get('button[type=submit]').click();
cy.getByCy('yes').click();
// Invalid radius input: empty, under 50 or over 5000
checkRadiusInput();
// Valid radius input
cy.get('#radius').clear().type(100);
cy.getByCy('nextStep').click();
cy.getByCy('done').click();
cy.getByCy('yes').click();
cy.getByCy('done').click();
cy.getByCy(`location-${NEW_BUILDING_LOCATION}`);
});
});
});
});
......@@ -6,88 +6,108 @@ import {
RESTAURANT_TYPE,
NEW_RESTAURANT_LOCATION,
} from '../../helpers/locations';
import { checkRadiusInput } from '../../helpers/inputValidation.helper';
import {
checkRadiusInput,
defaultLocationNameShouldBeRejected,
checkLocationNameIsUnique,
} from '../../helpers/inputValidation.helper';
describe('Create restaurant location', () => {
beforeEach(() => login());
afterEach(() => removeLocation(NEW_RESTAURANT_LOCATION));
describe('Without extra information', () => {
it('generate location without tables and auto checkout', () => {
context('Create restaurant location', () => {
describe('Location name validation', () => {
beforeEach(() => login());
it('checks if the location name is the default name', () => {
cy.getByCy(`createLocation-${E2E_DEFAULT_LOCATION_GROUP}`).click();
// Select type
cy.getByCy(RESTAURANT_TYPE).click();
// Enter name
cy.get('#locationName').type(NEW_RESTAURANT_LOCATION);
cy.getByCy('nextStep').click();
// Same address
cy.getByCy('yes').click();
//Enter phone
cy.get('#phone').type(E2E_PHONE_NUMBER);
cy.getByCy('nextStep').click();
// Select indoor
cy.getByCy('indoorSelection').click();
cy.getByCy('selectIndoor').