From bb5c162aac242cf3afffd145e9ff77f153dbbd36 Mon Sep 17 00:00:00 2001 From: Lias Kleisa Date: Wed, 22 Feb 2023 13:22:19 +0100 Subject: [PATCH 01/11] Add new email regex for person edit and rename file person edit to person form --- frontend/app/components/person-edit.js | 4 ++-- frontend/app/validations/person-edit.js | 9 --------- frontend/app/validations/person-form.js | 17 +++++++++++++++++ 3 files changed, 19 insertions(+), 11 deletions(-) delete mode 100644 frontend/app/validations/person-edit.js create mode 100644 frontend/app/validations/person-form.js diff --git a/frontend/app/components/person-edit.js b/frontend/app/components/person-edit.js index 7b9275676..818a9a90b 100644 --- a/frontend/app/components/person-edit.js +++ b/frontend/app/components/person-edit.js @@ -6,10 +6,10 @@ import { getNames as countryNames } from "ember-i18n-iso-countries"; import { on } from "@ember/object/evented"; import { EKMixin, keyUp } from "ember-keyboard"; import Person from "../models/person"; -import PersonEditValidations from "../validations/person-edit"; +import PersonFormValidations from "../validations/person-form"; export default ApplicationComponent.extend(EKMixin, { - PersonEditValidations, + PersonFormValidations, store: service(), intl: service(), session: service("keycloak-session"), diff --git a/frontend/app/validations/person-edit.js b/frontend/app/validations/person-edit.js deleted file mode 100644 index 6582aad48..000000000 --- a/frontend/app/validations/person-edit.js +++ /dev/null @@ -1,9 +0,0 @@ -import { validatePresence } from "ember-changeset-validations/validators"; - -export default { - name: [validatePresence(true)], - email: [validatePresence(true)], - title: [validatePresence(true)], - birthdate: [validatePresence(true)], - location: [validatePresence(true)] -}; diff --git a/frontend/app/validations/person-form.js b/frontend/app/validations/person-form.js new file mode 100644 index 000000000..4590bfd8d --- /dev/null +++ b/frontend/app/validations/person-form.js @@ -0,0 +1,17 @@ +import { + validatePresence, + validateFormat +} from "ember-changeset-validations/validators"; +export default { + name: [validatePresence(true)], + email: [ + validatePresence(true), + validateFormat({ + type: "email", + message: "Gib eine gültige Email Adresse ein" + }) + ], + title: [validatePresence(true)], + birthdate: [validatePresence(true)], + location: [validatePresence(true)] +}; From 58620e8c9a8d479324fa18adb4d446579b677cb6 Mon Sep 17 00:00:00 2001 From: Lias Kleisa Date: Wed, 22 Feb 2023 13:40:08 +0100 Subject: [PATCH 02/11] Add email validation for create new person in backend --- app/models/person.rb | 4 +++- frontend/translations/de.yml | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/app/models/person.rb b/app/models/person.rb index faaad804a..f468b673c 100644 --- a/app/models/person.rb +++ b/app/models/person.rb @@ -44,10 +44,12 @@ class Person < ApplicationRecord has_many :roles, through: :person_roles validates :birthdate, :location, :name, :nationality, - :title, :marital_status, presence: true + :title, :marital_status, :email, presence: true validates :location, :name, :title, :email, :shortname, length: { maximum: 100 } + validates :email, format: { with: /\A[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}\z/, message: "Format nicht gültig" } + validates :nationality, inclusion: { in: ISO3166::Country.all.collect(&:alpha2) } validates :nationality2, diff --git a/frontend/translations/de.yml b/frontend/translations/de.yml index 74b22473f..b97a5689d 100644 --- a/frontend/translations/de.yml +++ b/frontend/translations/de.yml @@ -125,6 +125,7 @@ person: title: Titel projects: Projekte personCompetences: Kompetenzen + email: Email personCompetence: category: Kategorie offer: Angebot From 3c423ff64cde5d24f93da4d2b6b2485c48d41372 Mon Sep 17 00:00:00 2001 From: Lias Kleisa Date: Mon, 27 Feb 2023 08:05:08 +0100 Subject: [PATCH 03/11] Add german validation message and rename person form to person edit --- frontend/app/components/person-edit.js | 4 ++-- frontend/app/validations/{person-form.js => person-edit.js} | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) rename frontend/app/validations/{person-form.js => person-edit.js} (82%) diff --git a/frontend/app/components/person-edit.js b/frontend/app/components/person-edit.js index 818a9a90b..7b9275676 100644 --- a/frontend/app/components/person-edit.js +++ b/frontend/app/components/person-edit.js @@ -6,10 +6,10 @@ import { getNames as countryNames } from "ember-i18n-iso-countries"; import { on } from "@ember/object/evented"; import { EKMixin, keyUp } from "ember-keyboard"; import Person from "../models/person"; -import PersonFormValidations from "../validations/person-form"; +import PersonEditValidations from "../validations/person-edit"; export default ApplicationComponent.extend(EKMixin, { - PersonFormValidations, + PersonEditValidations, store: service(), intl: service(), session: service("keycloak-session"), diff --git a/frontend/app/validations/person-form.js b/frontend/app/validations/person-edit.js similarity index 82% rename from frontend/app/validations/person-form.js rename to frontend/app/validations/person-edit.js index 4590bfd8d..1023550f4 100644 --- a/frontend/app/validations/person-form.js +++ b/frontend/app/validations/person-edit.js @@ -5,7 +5,7 @@ import { export default { name: [validatePresence(true)], email: [ - validatePresence(true), + validatePresence({ presence: true, message: "Email kann nicht leer sein" }), validateFormat({ type: "email", message: "Gib eine gültige Email Adresse ein" From ba7f0f5ce0e73c1ed643e1b889d4db56bbef8543 Mon Sep 17 00:00:00 2001 From: Lias Kleisa Date: Mon, 27 Feb 2023 08:17:27 +0100 Subject: [PATCH 04/11] Make rubocop happy --- app/models/person.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/models/person.rb b/app/models/person.rb index f468b673c..85d09d036 100644 --- a/app/models/person.rb +++ b/app/models/person.rb @@ -48,7 +48,9 @@ class Person < ApplicationRecord validates :location, :name, :title, :email, :shortname, length: { maximum: 100 } - validates :email, format: { with: /\A[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}\z/, message: "Format nicht gültig" } + validates :email, + format: { with: /\A[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}\z/, + message: 'Format nicht gültig' } validates :nationality, inclusion: { in: ISO3166::Country.all.collect(&:alpha2) } From 350a411bdb404259fa3ab193b2c1418a3cbcdbfe Mon Sep 17 00:00:00 2001 From: Lias Kleisa Date: Mon, 27 Feb 2023 15:50:16 +0100 Subject: [PATCH 05/11] Write backend test for email validation --- spec/models/person_spec.rb | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/spec/models/person_spec.rb b/spec/models/person_spec.rb index 1c1efa042..6246e060d 100644 --- a/spec/models/person_spec.rb +++ b/spec/models/person_spec.rb @@ -73,6 +73,30 @@ end end + context 'email' do + + it 'should be invalid when email is nil' do + person = people(:bob) + person.email = nil + expect(person).not_to be_valid + expect(person.errors.messages[:email].first).to eq('muss ausgefüllt werden') + end + + it 'should be invalid when email format is invalid' do + person = people(:bob) + person.email = "email" + expect(person).not_to be_valid + expect(person.errors.messages[:email].first).to eq('Format nicht gültig') + end + + it 'should be valid when email format is correct' do + person = people(:bob) + person.email = "bob@puzzle.ch" + expect(person).to be_valid + end + + end + it 'should not be more than 100 characters' do person = people(:bob) person.location = SecureRandom.hex(100) From a128c8c45199863971fa1c1859afac5d1a55bb84 Mon Sep 17 00:00:00 2001 From: Lias Kleisa Date: Mon, 27 Feb 2023 16:00:48 +0100 Subject: [PATCH 06/11] Write frontend test for email validation --- .../components/person-edit-test.js | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/frontend/tests/integration/components/person-edit-test.js b/frontend/tests/integration/components/person-edit-test.js index 353688f40..042d28d18 100644 --- a/frontend/tests/integration/components/person-edit-test.js +++ b/frontend/tests/integration/components/person-edit-test.js @@ -75,4 +75,47 @@ module("Integration | Component | person-edit", function(hooks) { .includes("Birthdate can't be blank") ); }); + + test("it renders person-edit with validation error at empty email", async function(assert) { + let person = run(() => + this.owner.lookup("service:store").createRecord("person") + ); + person.name = "Hans Rudolf"; + person.title = "Construction Consultant"; + person.location = "Bern"; + person.birthdate = new Date(2019, 1, 19); + person.shortname = "HR"; + this.set("person", person); + + await render(hbs`{{person-edit person=person}}`); + this.$("button")[0].click(); + await settled(); + assert.ok( + this.$("#validation-error") + .text() + .includes("Email kann nicht leer sein") + ); + }); + + test("it renders person-edit with validation error at invalid email", async function(assert) { + let person = run(() => + this.owner.lookup("service:store").createRecord("person") + ); + person.name = "Hans Rudolf"; + person.email = "hans"; + person.title = "Construction Consultant"; + person.location = "Bern"; + person.birthdate = new Date(2019, 1, 19); + person.shortname = "HR"; + this.set("person", person); + + await render(hbs`{{person-edit person=person}}`); + this.$("button")[0].click(); + await settled(); + assert.ok( + this.$("#validation-error") + .text() + .includes("Gib eine gültige Email Adresse ein") + ); + }); }); From 74a66511408024362608a0df243f1b97e342c35b Mon Sep 17 00:00:00 2001 From: Lias Kleisa Date: Wed, 1 Mar 2023 09:40:27 +0100 Subject: [PATCH 07/11] Write Acceptance test for invalid email in person new --- .../app/templates/components/person-new.hbs | 12 ++-- .../tests/acceptance/create-person-test.js | 26 +++++++++ frontend/tests/pages/people-new.js | 56 +++++++++++++++++-- 3 files changed, 83 insertions(+), 11 deletions(-) diff --git a/frontend/app/templates/components/person-new.hbs b/frontend/app/templates/components/person-new.hbs index 2d458decc..95953d3f8 100644 --- a/frontend/app/templates/components/person-new.hbs +++ b/frontend/app/templates/components/person-new.hbs @@ -13,13 +13,13 @@ - + - + - + @@ -47,7 +47,7 @@ {{/if}}
- +
@@ -81,7 +81,7 @@
- +
@@ -132,7 +132,7 @@ - + diff --git a/frontend/tests/acceptance/create-person-test.js b/frontend/tests/acceptance/create-person-test.js index d0d6e509f..54040275c 100644 --- a/frontend/tests/acceptance/create-person-test.js +++ b/frontend/tests/acceptance/create-person-test.js @@ -4,6 +4,7 @@ import { openDatepicker } from "ember-pikaday/helpers/pikaday"; import $ from "jquery"; import setupApplicationTest from "frontend/tests/helpers/setup-application-test"; import { currentURL } from "@ember/test-helpers"; +import { selectChoose } from "ember-power-select/test-support"; module("Acceptance | create person", function(hooks) { setupApplicationTest(hooks); @@ -77,4 +78,29 @@ module("Acceptance | create person", function(hooks) { assert.equal(currentURL(), "/people/new"); // TODO expect errors! }); + + test("should display error when email is invalid", async function(assert) { + await page.newPersonPage.visit(); + assert.equal(currentURL(), "/people/new"); + + page.newPersonPage.toggleNewForm(); + + await page.newForm.name("Findus"); + await page.newForm.title("Sofware Developer"); + await page.newForm.shortname("FI"); + await page.newForm.location("Bern"); + + let interactor = openDatepicker($(".birthdate_pikaday > input")); + + interactor.selectDate(new Date(2019, 1, 19)); + + await selectChoose("#department", "/dev/ruby"); + await selectChoose("#company", "Bewerber"); + await selectChoose("#maritalStatus", ".ember-power-select-option", 0); + + const button = document.querySelector("#submit-button"); + button.click(); + + await assert.dom().includesText("Format nicht gültig"); + }); }); diff --git a/frontend/tests/pages/people-new.js b/frontend/tests/pages/people-new.js index 6c8208e01..288f12a43 100644 --- a/frontend/tests/pages/people-new.js +++ b/frontend/tests/pages/people-new.js @@ -4,7 +4,8 @@ import { visitable, fillable, clickable, - text + text, + collection } from "ember-cli-page-object"; const { resolve } = RSVP; @@ -13,10 +14,12 @@ export default create({ newPersonPage: { visit: visitable("/people/new"), submit: clickable("#submit-button"), + toggleNewFormButton: clickable("[data-test-person-new-form-toggle]"), + toggleNationalitiesCheckbox: clickable("#toggle-nationalities-id"), - name: fillable('[name="person[name]"]'), - title: fillable('[name="person[title]"]'), - location: fillable('[name="person[location]"]'), + toggleNewForm() { + return this.newForm; + }, async createPerson(person) { await Object.keys(person).reduce( @@ -28,14 +31,57 @@ export default create({ } }, + newForm: { + scope: "#profil", + submit: clickable('[type="submit"]'), + name: fillable('[name="name"]'), + email: fillable('[name="email"]'), + shortname: fillable('[name="shortname"]'), + title: fillable('[name="title"]'), + location: fillable('[name="location"]'), + rolePercent: fillable('[name="rolePercent"]') + }, + profileData: { name: text("#data-test-person-name"), + email: text("#data-test-person-email"), title: text("#data-test-person-title"), role: text("#data-test-person-role"), + department: text("#data-test-person-department"), + company: text("#data-test-person-company"), birthdate: text("#data-test-person-birthdate"), nationalities: text("#data-test-person-nationalities"), location: text("#data-test-person-location"), language: text("[data-test-person-language]", { multiple: true }), - maritalStatus: text("#data-test-person-marital-status") + maritalStatus: text("#data-test-person-marital-status"), + shortname: text("#data-test-person-shortname") + }, + + competences: { + toggleForm: clickable("[data-test-competences-edit-form-toggle]"), + submit: clickable("#submit-button"), + + list: collection({ + itemScope: ".competence-entity", + item: { + text: text() + } + }) + }, + + educations: { + amountOf: text("#amount-of-educations"), + toggleForm: clickable("#educations-content-show .zeile"), + + list: collection({ + itemScope: ".education-entity", + item: { + text: text() + } + }), + + submit: clickable("#submit-education-button"), + delete: clickable("#delete-education-icon #deleteButton"), + confirm: clickable("#delete-button") } }); From e58aa743ad40edf14b431100f6e87536b771108f Mon Sep 17 00:00:00 2001 From: Lias Kleisa Date: Wed, 1 Mar 2023 12:58:52 +0100 Subject: [PATCH 08/11] Use other click method to call submit button --- frontend/tests/acceptance/create-person-test.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/tests/acceptance/create-person-test.js b/frontend/tests/acceptance/create-person-test.js index 54040275c..22ac7e51c 100644 --- a/frontend/tests/acceptance/create-person-test.js +++ b/frontend/tests/acceptance/create-person-test.js @@ -2,6 +2,7 @@ import { module, test, skip } from "qunit"; import page from "frontend/tests/pages/people-new"; import { openDatepicker } from "ember-pikaday/helpers/pikaday"; import $ from "jquery"; +import { click } from "@ember/test-helpers"; import setupApplicationTest from "frontend/tests/helpers/setup-application-test"; import { currentURL } from "@ember/test-helpers"; import { selectChoose } from "ember-power-select/test-support"; @@ -98,9 +99,8 @@ module("Acceptance | create person", function(hooks) { await selectChoose("#company", "Bewerber"); await selectChoose("#maritalStatus", ".ember-power-select-option", 0); - const button = document.querySelector("#submit-button"); - button.click(); + await click("button#submit-button"); - await assert.dom().includesText("Format nicht gültig"); + assert.dom().includesText("Format nicht gültig"); }); }); From 0858d1fb58abdbcaeb8090f1abbf704f92e4fbba Mon Sep 17 00:00:00 2001 From: Lias Kleisa Date: Fri, 3 Mar 2023 08:11:38 +0100 Subject: [PATCH 09/11] Remove unused code in people-new.js --- frontend/tests/pages/people-new.js | 33 ++---------------------------- 1 file changed, 2 insertions(+), 31 deletions(-) diff --git a/frontend/tests/pages/people-new.js b/frontend/tests/pages/people-new.js index 288f12a43..5bc9b00c6 100644 --- a/frontend/tests/pages/people-new.js +++ b/frontend/tests/pages/people-new.js @@ -1,11 +1,10 @@ import RSVP from "rsvp"; import { + clickable, create, - visitable, fillable, - clickable, text, - collection + visitable } from "ember-cli-page-object"; const { resolve } = RSVP; @@ -55,33 +54,5 @@ export default create({ language: text("[data-test-person-language]", { multiple: true }), maritalStatus: text("#data-test-person-marital-status"), shortname: text("#data-test-person-shortname") - }, - - competences: { - toggleForm: clickable("[data-test-competences-edit-form-toggle]"), - submit: clickable("#submit-button"), - - list: collection({ - itemScope: ".competence-entity", - item: { - text: text() - } - }) - }, - - educations: { - amountOf: text("#amount-of-educations"), - toggleForm: clickable("#educations-content-show .zeile"), - - list: collection({ - itemScope: ".education-entity", - item: { - text: text() - } - }), - - submit: clickable("#submit-education-button"), - delete: clickable("#delete-education-icon #deleteButton"), - confirm: clickable("#delete-button") } }); From 6ea41dcbdfaca9399ec534185de5c898501d0865 Mon Sep 17 00:00:00 2001 From: Lias Kleisa Date: Fri, 3 Mar 2023 09:57:59 +0100 Subject: [PATCH 10/11] Fix frontend test for email validation on create person --- frontend/app/components/person-new.js | 3 +- .../tests/acceptance/create-person-test.js | 46 +++++++++++++++++-- 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/frontend/app/components/person-new.js b/frontend/app/components/person-new.js index 1512ef51d..82f3d1715 100644 --- a/frontend/app/components/person-new.js +++ b/frontend/app/components/person-new.js @@ -4,6 +4,7 @@ import { computed } from "@ember/object"; import { isBlank } from "@ember/utils"; import { getNames as countryNames } from "ember-i18n-iso-countries"; import Person from "../models/person"; +import config from "../config/environment"; export default ApplicationComponent.extend({ intl: service(), @@ -99,7 +100,7 @@ export default ApplicationComponent.extend({ `person.${attribute}` ); this.get("notify").alert(`${translated_attribute} ${message}`, { - closeAfter: 8000 + closeAfter: config.environment === "test" ? null : 8000 }); }); }); diff --git a/frontend/tests/acceptance/create-person-test.js b/frontend/tests/acceptance/create-person-test.js index 22ac7e51c..c7bc63928 100644 --- a/frontend/tests/acceptance/create-person-test.js +++ b/frontend/tests/acceptance/create-person-test.js @@ -80,7 +80,7 @@ module("Acceptance | create person", function(hooks) { // TODO expect errors! }); - test("should display error when email is invalid", async function(assert) { + test("should display two error when email is empty", async function(assert) { await page.newPersonPage.visit(); assert.equal(currentURL(), "/people/new"); @@ -95,12 +95,50 @@ module("Acceptance | create person", function(hooks) { interactor.selectDate(new Date(2019, 1, 19)); - await selectChoose("#department", "/dev/ruby"); - await selectChoose("#company", "Bewerber"); + await selectChoose("#department", "/dev/one"); + await selectChoose("#company", "Firma"); + await selectChoose("#maritalStatus", ".ember-power-select-option", 0); + + await click("button#submit-button"); + + assert.equal( + document.querySelectorAll(".ember-notify")[0].querySelector(".message") + .innerText, + "Email muss ausgefüllt werden" + ); + assert.equal( + document.querySelectorAll(".ember-notify")[1].querySelector(".message") + .innerText, + "Email Format nicht gültig" + ); + }); + + test("should display one error when email format is invalid", async function(assert) { + await page.newPersonPage.visit(); + assert.equal(currentURL(), "/people/new"); + + page.newPersonPage.toggleNewForm(); + + await page.newForm.name("Findus"); + await page.newForm.email("findus.puzzle"); + await page.newForm.title("Sofware Developer"); + await page.newForm.shortname("FI"); + await page.newForm.location("Bern"); + + let interactor = openDatepicker($(".birthdate_pikaday > input")); + + interactor.selectDate(new Date(2019, 1, 19)); + + await selectChoose("#department", "/dev/one"); + await selectChoose("#company", "Firma"); await selectChoose("#maritalStatus", ".ember-power-select-option", 0); await click("button#submit-button"); - assert.dom().includesText("Format nicht gültig"); + assert.equal( + document.querySelectorAll(".ember-notify")[0].querySelector(".message") + .innerText, + "Email Format nicht gültig" + ); }); }); From aca253c8ef174c1396320f202cbb6e3395140fe6 Mon Sep 17 00:00:00 2001 From: Lias Kleisa Date: Fri, 3 Mar 2023 14:38:44 +0100 Subject: [PATCH 11/11] Fix type fault --- frontend/tests/acceptance/create-person-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/tests/acceptance/create-person-test.js b/frontend/tests/acceptance/create-person-test.js index c7bc63928..237a240bf 100644 --- a/frontend/tests/acceptance/create-person-test.js +++ b/frontend/tests/acceptance/create-person-test.js @@ -80,7 +80,7 @@ module("Acceptance | create person", function(hooks) { // TODO expect errors! }); - test("should display two error when email is empty", async function(assert) { + test("should display two errors when email is empty", async function(assert) { await page.newPersonPage.visit(); assert.equal(currentURL(), "/people/new");