diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 0000000..b7c0f63 --- /dev/null +++ b/.coveragerc @@ -0,0 +1,3 @@ +[run] +omit = + project/cli/database.py \ No newline at end of file diff --git a/cypress/integration/login_spec.js b/cypress/integration/login_spec.js new file mode 100644 index 0000000..4eb596c --- /dev/null +++ b/cypress/integration/login_spec.js @@ -0,0 +1,28 @@ +describe('Login', () => { + it('user log in', () => { + cy.visit('/login') + + // Blank + cy.get('#submit').click() + cy.assertRequired('email') + cy.assertRequired('password') + + // Email + cy.get('#email').type("invalidmail") + cy.assertInvalid('email', 'Geben Sie bitte eine gültige E-Mail-Adresse ein.') + + cy.get('#email').clear().type("test@test.de") + cy.assertValid('email') + + // Password + cy.get('#password').type("password") + cy.assertValid('password') + + // Submit + cy.get('#submit').click() + + cy.url().should('include', '/manage') + cy.get('h1').should('contain', 'Organisationen') + cy.getCookie('session').should('exist') + }) + }) \ No newline at end of file diff --git a/cypress/integration/profile_spec.js b/cypress/integration/profile_spec.js new file mode 100644 index 0000000..ba7f9b5 --- /dev/null +++ b/cypress/integration/profile_spec.js @@ -0,0 +1,7 @@ +describe('Profile', () => { + it('profile', () => { + cy.login() + cy.visit('/profile') + cy.get('h1').should('contain', 'test@test.de') + }) + }) \ No newline at end of file diff --git a/cypress/integration/register_spec.js b/cypress/integration/register_spec.js index 480548c..ea13710 100644 --- a/cypress/integration/register_spec.js +++ b/cypress/integration/register_spec.js @@ -1,15 +1,41 @@ describe('Register', () => { - beforeEach(() => { - cy.logexec('flask database reset --seed') - }) - it('registers user', () => { cy.visit('/register') - cy.get('input[name=email]').type("firstname.lastname@gmail.com") - cy.get('input[name=password]').type("iloveoveda{enter}") - cy.get('input[name=password_confirm]').type("iloveoveda{enter}") - cy.get('input[name=accept_tos]').check() - cy.get('input[name=submit]').click() + + // Blank + cy.get('#submit').click() + cy.assertRequired('email') + cy.assertRequired('password') + cy.assertRequired('password_confirm') + cy.assertRequired('accept_tos') + + // Email + cy.get('#email').type("invalidmail") + cy.assertInvalid('email', 'Geben Sie bitte eine gültige E-Mail-Adresse ein.') + + cy.get('#email').clear().type("test@test.de") + cy.assertInvalid('email', 'Mit dieser E-Mail existiert bereits ein Account.') + + cy.get('#email').clear().type("firstname.lastname@gmail.com") + cy.assertValid('email') + + // Password + cy.get('#password').type("short") + cy.assertInvalid('password', 'Geben Sie bitte mindestens 8 Zeichen ein.') + + cy.get('#password').clear().type("iloveoveda") + cy.assertValid('password') + + // Confirm password + cy.get('#password_confirm').type("different") + cy.assertInvalid('password_confirm', 'Wiederholen Sie bitte denselben Wert.') + + cy.get('#password_confirm').clear().type("iloveoveda") + cy.assertValid('password_confirm') + + // Submit + cy.get('#accept_tos').check() + cy.get('#submit').click() cy.url().should('eq', Cypress.config().baseUrl + '/') cy.get('div.alert').should('contain', 'Bestätigungsanleitung') diff --git a/cypress/support/commands.js b/cypress/support/commands.js index 5bad9d4..cfcc692 100644 --- a/cypress/support/commands.js +++ b/cypress/support/commands.js @@ -1,28 +1,3 @@ -// *********************************************** -// This example commands.js shows you how to -// create various custom commands and overwrite -// existing commands. -// -// For more comprehensive examples of custom -// commands please read more here: -// https://on.cypress.io/custom-commands -// *********************************************** -// -// -// -- This is a parent command -- -// Cypress.Commands.add('login', (email, password) => { ... }) -// -// -// -- This is a child command -- -// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... }) -// -// -// -- This is a dual command -- -// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... }) -// -// -// -- This will overwrite an existing command -- -// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... }) Cypress.Commands.add('logexec', (command) => { cy.exec(command, { failOnNonZeroExit: false }).then(result => { if (result.code) { @@ -32,4 +7,33 @@ Cypress.Commands.add('logexec', (command) => { Stderr:\n${result.stderr}`); } }) -}) \ No newline at end of file +}) + +Cypress.Commands.add('setup', () => { + cy.logexec('flask database reset --seed') + cy.logexec('flask user create test@test.de password --confirm') +}) + +Cypress.Commands.add('assertValid', (fieldId) => { + cy.get('#' + fieldId).should('have.class', 'is-valid') + cy.get('#' + fieldId + '-error').should('be.empty') +}) + + +Cypress.Commands.add('assertInvalid', (fieldId, msg) => { + cy.get('#' + fieldId).should('have.class', 'is-invalid') + cy.get('#' + fieldId + '-error').should('contain', msg) +}) + +Cypress.Commands.add('assertRequired', (fieldId) => { + cy.assertInvalid(fieldId, 'Pflichtfeld') +}) + +Cypress.Commands.add('login', (email = "test@test.de", password = "password") => { + cy.visit('/login') + cy.get('#email').type(email) + cy.get('#password').type(password) + cy.get('#submit').click() + cy.url().should('include', '/manage') + cy.getCookie('session').should('exist') +}) diff --git a/cypress/support/index.js b/cypress/support/index.js index d68db96..0aa354e 100644 --- a/cypress/support/index.js +++ b/cypress/support/index.js @@ -1,20 +1,5 @@ -// *********************************************************** -// This example support/index.js is processed and -// loaded automatically before your test files. -// -// This is a great place to put global configuration and -// behavior that modifies Cypress. -// -// You can change the location of this file or turn off -// automatically serving support files with the -// 'supportFile' configuration option. -// -// You can read more here: -// https://on.cypress.io/configuration -// *********************************************************** - -// Import commands.js using ES2015 syntax: import './commands' -// Alternatively you can use CommonJS syntax: -// require('./commands') +beforeEach(() => { + cy.setup() +}) \ No newline at end of file diff --git a/project/cli/database.py b/project/cli/database.py index d56875a..ec09cdc 100644 --- a/project/cli/database.py +++ b/project/cli/database.py @@ -1,4 +1,3 @@ -# pragma: no cover import click from flask.cli import AppGroup from sqlalchemy import MetaData diff --git a/project/cli/user.py b/project/cli/user.py index b496ce5..0ced9fe 100644 --- a/project/cli/user.py +++ b/project/cli/user.py @@ -1,8 +1,13 @@ import click from flask.cli import AppGroup +from flask_security.confirmable import confirm_user from project import app, db -from project.services.user import add_admin_roles_to_user +from project.services.user import ( + add_admin_roles_to_user, + create_user, + find_user_by_email, +) user_cli = AppGroup("user") @@ -15,4 +20,27 @@ def add_admin_roles(email): click.echo(f"Admin roles were added to {email}.") +@user_cli.command("create") +@click.argument("email") +@click.argument("password") +@click.option("--confirm/--no-confirm", default=False) +def create(email, password, confirm): + user = create_user(email, password) + + if confirm: + confirm_user(user) + + db.session.commit() + click.echo(f"Created user {email}.") + + +@user_cli.command("confirm") +@click.argument("email") +def confirm(email): + user = find_user_by_email(email) + confirm_user(user) + db.session.commit() + click.echo(f"Confirmed user {email}.") + + app.cli.add_command(user_cli) diff --git a/project/templates/security/login_user.html b/project/templates/security/login_user.html index 6e9e01a..7549772 100644 --- a/project/templates/security/login_user.html +++ b/project/templates/security/login_user.html @@ -1,11 +1,23 @@ {% extends "layout.html" %} -{% from "_macros.html" import render_field_with_errors, render_field, render_field_errors %} +{% from "_macros.html" import render_jquery_steps_header, render_field_with_errors, render_field, render_field_errors %} + +{% block header %} +{{ render_jquery_steps_header() }} + + +{% endblock %} {% block content %}