diff --git a/certif/app/components/language-switcher.gjs b/certif/app/components/language-switcher.gjs
new file mode 100644
index 00000000000..b198cdb229d
--- /dev/null
+++ b/certif/app/components/language-switcher.gjs
@@ -0,0 +1,43 @@
+import PixSelect from '@1024pix/pix-ui/components/pix-select';
+import { service } from '@ember/service';
+import Component from '@glimmer/component';
+import { t } from 'ember-intl';
+import { FRENCH_INTERNATIONAL_LOCALE } from 'pix-certif/services/locale';
+
+export default class LanguageSwitcher extends Component {
+ @service locale;
+
+ get alphabeticallySortedLanguages() {
+ const availableLanguages = this.locale.getAvailableLanguages();
+
+ const options = Object.entries(availableLanguages)
+ .filter(([_, config]) => config.languageSwitcherDisplayed)
+ .map(([key, config]) => ({
+ label: config.value,
+ value: key,
+ }));
+
+ const optionsWithoutFrSortedByLabel = options
+ .filter((option) => option.value !== FRENCH_INTERNATIONAL_LOCALE)
+ .sort((option) => option.label);
+
+ const frenchLanguageOption = options.find((option) => option.value === FRENCH_INTERNATIONAL_LOCALE);
+
+ return [frenchLanguageOption, ...optionsWithoutFrSortedByLabel];
+ }
+
+
+
+ <:label>{{t 'common.forms.login.choose-language-aria-label'}}
+
+
+}
diff --git a/certif/app/components/language-switcher.hbs b/certif/app/components/language-switcher.hbs
deleted file mode 100644
index 43cd7007954..00000000000
--- a/certif/app/components/language-switcher.hbs
+++ /dev/null
@@ -1,12 +0,0 @@
-
- <:label>{{t "common.forms.login.choose-language-aria-label"}}
-
\ No newline at end of file
diff --git a/certif/app/components/language-switcher.js b/certif/app/components/language-switcher.js
deleted file mode 100644
index 597877eb663..00000000000
--- a/certif/app/components/language-switcher.js
+++ /dev/null
@@ -1,35 +0,0 @@
-import { action } from '@ember/object';
-import Component from '@glimmer/component';
-import languages from 'pix-certif/languages';
-
-const FRENCH_LANGUAGE = 'fr';
-
-export default class LanguageSwitcher extends Component {
- availableLanguages = this.mapToOptions(languages);
-
- get selectedLanguage() {
- return this.args.selectedLanguage;
- }
-
- @action
- onChange(value) {
- this.args.onLanguageChange(value);
- }
-
- mapToOptions(languages) {
- const options = Object.entries(languages)
- .filter(([_, config]) => config.languageSwitcherDisplayed)
- .map(([key, config]) => ({
- label: config.value,
- value: key,
- }));
-
- const optionsWithoutFrSortedByLabel = options
- .filter((option) => option.value !== FRENCH_LANGUAGE)
- .sort((option) => option.label);
-
- const frenchLanguageOption = options.find((option) => option.value === FRENCH_LANGUAGE);
-
- return [frenchLanguageOption, ...optionsWithoutFrSortedByLabel];
- }
-}
diff --git a/certif/app/components/login-form.hbs b/certif/app/components/login-form.hbs
deleted file mode 100644
index c0b9d6bb11c..00000000000
--- a/certif/app/components/login-form.hbs
+++ /dev/null
@@ -1,67 +0,0 @@
-
-
diff --git a/certif/tests/integration/components/auth/toggable-login-form-test.js b/certif/tests/integration/components/auth/toggable-login-form-test.js
index 4d69303aee2..8f30634aba7 100644
--- a/certif/tests/integration/components/auth/toggable-login-form-test.js
+++ b/certif/tests/integration/components/auth/toggable-login-form-test.js
@@ -34,6 +34,7 @@ module('Integration | Component | Auth::ToggableLoginForm', function (hooks) {
// then
assert.dom(screen.getByRole('textbox', { name: emailInputLabel })).exists();
assert.dom(screen.getByLabelText(passwordInputLabel)).exists();
+ assert.dom(screen.getByText(loginLabel)).exists();
});
test('[a11y] it should display a message that all inputs are required', async function (assert) {
diff --git a/certif/tests/integration/components/language-switcher-test.gjs b/certif/tests/integration/components/language-switcher-test.gjs
new file mode 100644
index 00000000000..0074ef57809
--- /dev/null
+++ b/certif/tests/integration/components/language-switcher-test.gjs
@@ -0,0 +1,139 @@
+import { render } from '@1024pix/ember-testing-library';
+import { click } from '@ember/test-helpers';
+import { t } from 'ember-intl/test-support';
+import LanguageSwitcher from 'pix-certif/components/language-switcher';
+import { module, test } from 'qunit';
+import sinon from 'sinon';
+
+import setupIntlRenderingTest from '../../helpers/setup-intl-rendering';
+
+module('Integration | Component | Language Switcher', function (hooks) {
+ setupIntlRenderingTest(hooks);
+
+ let localeService;
+
+ let availableLanguages = {
+ en: {
+ value: 'English',
+ languageSwitcherDisplayed: true,
+ },
+ fr: {
+ value: 'Français',
+ languageSwitcherDisplayed: true,
+ },
+ el: {
+ value: 'Primitive Eldarìn',
+ languageSwitcherDisplayed: true,
+ },
+ si: {
+ value: 'Sindarìn',
+ languageSwitcherDisplayed: true,
+ },
+ };
+
+ hooks.beforeEach(function () {
+ localeService = this.owner.lookup('service:locale');
+ });
+
+ module('when component renders', function () {
+ test('displays a button with default option selected', async function (assert) {
+ // given
+ sinon.stub(localeService, 'getAvailableLanguages').returns(availableLanguages);
+
+ // when
+ const screen = await render();
+
+ // then
+ const selectALanguage = t('common.forms.login.choose-language-aria-label');
+
+ assert.dom(screen.getByRole('button', { name: selectALanguage })).includesText('English');
+ });
+ });
+
+ module('when component is clicked', function () {
+ test('displays a sorted list of available languages with french language first', async function (assert) {
+ // given
+ sinon.stub(localeService, 'getAvailableLanguages').returns(availableLanguages);
+
+ // when
+ const screen = await render();
+
+ const selectALanguage = t('common.forms.login.choose-language-aria-label');
+
+ await click(screen.getByRole('button', { name: selectALanguage }));
+ await screen.findByRole('listbox');
+
+ // then
+ const options = await screen.findAllByRole('option');
+ assert.dom(screen.getByRole('option', { name: 'English' })).exists();
+ const optionsInnerText = options.map((option) => {
+ return option.innerText;
+ });
+
+ assert.deepEqual(optionsInnerText, ['Français', 'English', 'Primitive Eldarìn', 'Sindarìn']);
+ });
+
+ test(`displays all languages with "languageSwitcherDisplayed" attribute at true`, async function (assert) {
+ // given
+ availableLanguages = {
+ en: {
+ value: 'English',
+ languageSwitcherDisplayed: true,
+ },
+ fr: {
+ value: 'Français',
+ languageSwitcherDisplayed: true,
+ },
+ el: {
+ value: 'Primitive Eldarìn',
+ languageSwitcherDisplayed: false,
+ },
+ si: {
+ value: 'Sindarìn',
+ languageSwitcherDisplayed: true,
+ },
+ };
+
+ sinon.stub(localeService, 'getAvailableLanguages').returns(availableLanguages);
+
+ const screen = await render();
+
+ // when
+ const selectALanguage = t('common.forms.login.choose-language-aria-label');
+
+ await click(screen.getByRole('button', { name: selectALanguage }));
+ await screen.findByRole('listbox');
+
+ // then
+ const options = await screen.findAllByRole('option');
+ assert.dom(screen.getByRole('option', { name: 'English' })).exists();
+ const optionsInnerText = options.map((option) => {
+ return option.innerText;
+ });
+
+ assert.deepEqual(optionsInnerText, ['Français', 'English', 'Sindarìn']);
+ });
+ });
+
+ module('when a language is selected', function () {
+ test('should display correct language', async function (assert) {
+ // given
+ const onLanguageChangeStub = sinon.stub();
+ sinon.stub(localeService, 'getAvailableLanguages').returns(availableLanguages);
+
+ // when
+ const screen = await render(
+ ,
+ );
+
+ const selectALanguage = t('common.forms.login.choose-language-aria-label');
+
+ await click(screen.getByRole('button', { name: selectALanguage }));
+ await screen.findByRole('listbox');
+ await click(screen.getByRole('option', { name: 'Français' }));
+
+ // then
+ assert.ok(onLanguageChangeStub.calledWithExactly('fr'));
+ });
+ });
+});
diff --git a/certif/tests/integration/components/language-switcher-test.js b/certif/tests/integration/components/language-switcher-test.js
deleted file mode 100644
index f0d77a3a287..00000000000
--- a/certif/tests/integration/components/language-switcher-test.js
+++ /dev/null
@@ -1,60 +0,0 @@
-import { render } from '@1024pix/ember-testing-library';
-import { click } from '@ember/test-helpers';
-import { hbs } from 'ember-cli-htmlbars';
-import { module, test } from 'qunit';
-import sinon from 'sinon';
-
-import setupIntlRenderingTest from '../../helpers/setup-intl-rendering';
-
-module('Integration | Component | Language Switcher', function (hooks) {
- setupIntlRenderingTest(hooks);
-
- module('when component renders', function () {
- test('displays a button with default option selected', async function (assert) {
- // when
- const screen = await render(hbs``);
-
- // then
- assert.dom(screen.getByRole('button', { name: 'Sélectionnez une langue' })).exists();
- });
- });
-
- module('when component is clicked', function () {
- test('displays a list of available languages with french language first', async function (assert) {
- // given
- const screen = await render(hbs``);
-
- // when
- await click(screen.getByRole('button', { name: 'Sélectionnez une langue' }));
- await screen.findByRole('listbox');
-
- // then
- const options = await screen.findAllByRole('option');
- assert.dom(screen.getByRole('option', { name: 'English' })).exists();
- const optionsInnerText = options.map((option) => {
- return option.innerText;
- });
-
- assert.deepEqual(optionsInnerText, ['Français', 'English']);
- });
- });
-
- module('when a language is selected', function () {
- test('calls onLanguageChange callback', async function (assert) {
- // given
- const onLanguageChangeStub = sinon.stub();
- this.set('onLanguageChange', onLanguageChangeStub);
- const screen = await render(
- hbs``,
- );
-
- // when
- await click(screen.getByRole('button', { name: 'Sélectionnez une langue' }));
- await screen.findByRole('listbox');
- await click(screen.getByRole('option', { name: 'Français' }));
-
- // then
- assert.ok(onLanguageChangeStub.calledWithExactly('fr'));
- });
- });
-});
diff --git a/certif/tests/integration/components/login-form-test.js b/certif/tests/integration/components/login-test.gjs
similarity index 80%
rename from certif/tests/integration/components/login-form-test.js
rename to certif/tests/integration/components/login-test.gjs
index fcaf65ed9b5..519f6f117dd 100644
--- a/certif/tests/integration/components/login-form-test.js
+++ b/certif/tests/integration/components/login-test.gjs
@@ -1,8 +1,8 @@
-import { render as renderScreen } from '@1024pix/ember-testing-library';
+import { render } from '@1024pix/ember-testing-library';
import Service from '@ember/service';
import { click, fillIn } from '@ember/test-helpers';
-import { hbs } from 'ember-cli-htmlbars';
import { t } from 'ember-intl/test-support';
+import Login from 'pix-certif/components/login';
import ENV from 'pix-certif/config/environment';
import { module, test } from 'qunit';
import { reject, resolve } from 'rsvp';
@@ -11,7 +11,7 @@ import sinon from 'sinon';
import setupIntlRenderingTest from '../../helpers/setup-intl-rendering';
const ApiErrorMessages = ENV.APP.API_ERROR_MESSAGES;
-module('Integration | Component | login-form', function (hooks) {
+module('Integration | Component | login', function (hooks) {
setupIntlRenderingTest(hooks);
let sessionStub;
@@ -26,7 +26,7 @@ module('Integration | Component | login-form', function (hooks) {
test('it should display login form', async function (assert) {
// when
- const screen = await renderScreen(hbs``);
+ const screen = await render();
// then
assert.dom(screen.getByRole('img', { name: 'Pix Certif' })).exists();
@@ -46,7 +46,7 @@ module('Integration | Component | login-form', function (hooks) {
return resolve();
});
const sessionServiceObserver = this.owner.lookup('service:session');
- const screen = await renderScreen(hbs``);
+ const screen = await render();
await fillIn(screen.getByRole('textbox', { name: 'Adresse e-mail' }), 'pix@example.net');
await fillIn(screen.getByLabelText('Mot de passe'), 'JeMeLoggue1024');
@@ -76,7 +76,7 @@ module('Integration | Component | login-form', function (hooks) {
};
sessionStub.authenticate.callsFake(() => reject(invalidCredentialsErrorMessage));
- const screen = await renderScreen(hbs``);
+ const screen = await render();
await fillIn(screen.getByRole('textbox', { name: 'Adresse e-mail' }), 'pix@example.net');
await fillIn(screen.getByLabelText('Mot de passe'), 'Mauvais mot de passe');
@@ -87,6 +87,30 @@ module('Integration | Component | login-form', function (hooks) {
assert.dom(screen.getByText(t(ApiErrorMessages.LOGIN_UNAUTHORIZED.I18N_KEY))).exists();
});
+ test('should authenticate user with trimmed email', async function (assert) {
+ // given
+ sessionStub.authenticate.callsFake(function (authenticator, email, password, scope) {
+ this.authenticator = authenticator;
+ this.email = email;
+ this.password = password;
+ this.scope = scope;
+ return resolve();
+ });
+ const sessionServiceObserver = this.owner.lookup('service:session');
+ const screen = await render();
+ await fillIn(screen.getByRole('textbox', { name: 'Adresse e-mail' }), ' email@example.net ');
+ await fillIn(screen.getByLabelText('Mot de passe'), 'JeMeLoggue1024');
+
+ // when
+ await click(screen.getByRole('button', { name: 'Je me connecte' }));
+
+ // then
+ assert.strictEqual(sessionServiceObserver.authenticator, 'authenticator:oauth2');
+ assert.strictEqual(sessionServiceObserver.email, 'email@example.net');
+ assert.strictEqual(sessionServiceObserver.password, 'JeMeLoggue1024');
+ assert.strictEqual(sessionServiceObserver.scope, 'pix-certif');
+ });
+
test('it displays a should change password message', async function (assert) {
// given
const errorResponse = {
@@ -98,7 +122,7 @@ module('Integration | Component | login-form', function (hooks) {
service.currentDomain = { getExtension: sinon.stub().returns('fr') };
sessionStub.authenticate.callsFake(() => reject(errorResponse));
- const screen = await renderScreen(hbs``);
+ const screen = await render();
await fillIn(screen.getByRole('textbox', { name: 'Adresse e-mail' }), 'pix@example.net');
await fillIn(screen.getByLabelText('Mot de passe'), 'Mauvais mot de passe');
@@ -139,7 +163,7 @@ module('Integration | Component | login-form', function (hooks) {
};
sessionStub.authenticate.callsFake(() => reject(notLinkedToOrganizationErrorMessage));
- const screen = await renderScreen(hbs``);
+ const screen = await render();
await fillIn(screen.getByRole('textbox', { name: 'Adresse e-mail' }), 'pix@example.net');
await fillIn(screen.getByLabelText('Mot de passe'), 'JeMeLoggue1024');
@@ -166,7 +190,7 @@ module('Integration | Component | login-form', function (hooks) {
};
sessionStub.authenticate.callsFake(() => reject(gatewayTimeoutErrorMessage));
- const screen = await renderScreen(hbs``);
+ const screen = await render();
await fillIn(screen.getByRole('textbox', { name: 'Adresse e-mail' }), 'pix@example.net');
await fillIn(screen.getByLabelText('Mot de passe'), 'JeMeLoggue1024');
@@ -185,7 +209,7 @@ module('Integration | Component | login-form', function (hooks) {
};
sessionStub.authenticate.callsFake(() => reject(msgErrorNotLinkedCertification));
- const screen = await renderScreen(hbs``);
+ const screen = await render();
await fillIn(screen.getByRole('textbox', { name: 'Adresse e-mail' }), 'pix@example.net');
await fillIn(screen.getByLabelText('Mot de passe'), 'JeMeLoggue1024');
@@ -199,7 +223,7 @@ module('Integration | Component | login-form', function (hooks) {
module('when an invitation is cancelled', function () {
test('it should display an error message', async function (assert) {
// given & when
- const screen = await renderScreen(hbs``);
+ const screen = await render();
// then
assert
@@ -217,7 +241,7 @@ module('Integration | Component | login-form', function (hooks) {
module('when an invitation has already been accepted', function () {
test('it should display an error message', async function (assert) {
// given & when
- const screen = await renderScreen(hbs``);
+ const screen = await render();
// then
assert
diff --git a/certif/tests/unit/components/language-switcher-test.js b/certif/tests/unit/components/language-switcher-test.js
deleted file mode 100644
index 7525efa9620..00000000000
--- a/certif/tests/unit/components/language-switcher-test.js
+++ /dev/null
@@ -1,111 +0,0 @@
-import { setupTest } from 'ember-qunit';
-import { module, test } from 'qunit';
-
-import createGlimmerComponent from '../../helpers/create-glimmer-component';
-
-module('Unit | Component | language-switcher', function (hooks) {
- setupTest(hooks);
-
- let component;
-
- hooks.beforeEach(function () {
- component = createGlimmerComponent('component:language-switcher');
- });
-
- module('#mapToOptions', function () {
- test('sorts languages with french international language first', function (assert) {
- // given
- const languages = {
- en: {
- value: 'English',
- languageSwitcherDisplayed: true,
- },
- fr: {
- value: 'Français',
- languageSwitcherDisplayed: true,
- },
- };
-
- // when
- const result = component.mapToOptions(languages);
-
- // then
- const expectedResult = {
- label: 'Français',
- value: 'fr',
- };
-
- assert.deepEqual(result[0], expectedResult);
- });
-
- test('sorts other languages by "value"', function (assert) {
- // given
- const languages = {
- en: {
- value: 'English',
- languageSwitcherDisplayed: true,
- },
- es: {
- value: 'Spanish',
- languageSwitcherDisplayed: true,
- },
- fr: {
- value: 'Français',
- languageSwitcherDisplayed: true,
- },
- };
-
- // when
- const result = component.mapToOptions(languages);
-
- // then
- const expectedResult = [
- {
- label: 'Français',
- value: 'fr',
- },
- {
- label: 'English',
- value: 'en',
- },
- {
- label: 'Spanish',
- value: 'es',
- },
- ];
- assert.deepEqual(result, expectedResult);
- });
-
- module('when languages have attribute "languageSwitcherDisplayed" at "false"', function () {
- test(`does not map these languages`, function (assert) {
- // given
- const languages = {
- fr: {
- value: 'Français',
- languageSwitcherDisplayed: true,
- },
- en: {
- value: 'English',
- languageSwitcherDisplayed: false,
- },
- es: {
- value: 'Spanish',
- languageSwitcherDisplayed: false,
- },
- };
-
- // when
- const result = component.mapToOptions(languages);
-
- // then
- const expectedResult = [
- {
- label: 'Français',
- value: 'fr',
- },
- ];
- assert.deepEqual(result, expectedResult);
- });
- });
- });
-});
diff --git a/certif/tests/unit/components/login-form-test.js b/certif/tests/unit/components/login-form-test.js
deleted file mode 100644
index ef7fc688ce5..00000000000
--- a/certif/tests/unit/components/login-form-test.js
+++ /dev/null
@@ -1,41 +0,0 @@
-import Service from '@ember/service';
-import { setupTest } from 'ember-qunit';
-import { module, test } from 'qunit';
-import sinon from 'sinon';
-
-import createGlimmerComponent from '../../helpers/create-glimmer-component';
-
-module('Unit | Component | login-form', (hooks) => {
- setupTest(hooks);
-
- const authenticateStub = sinon.stub().resolves();
- const expectedAuthenticator = 'authenticator:oauth2';
- const eventStub = { preventDefault: sinon.stub().returns() };
-
- let component;
-
- hooks.beforeEach(function () {
- const sessionStub = Service.create({
- authenticate: authenticateStub,
- });
-
- component = createGlimmerComponent('component:login-form');
- component.session = sessionStub;
- });
-
- module('#authenticate', () => {
- test('should authenticate user with trimmed email', async function (assert) {
- // given
- const emailWithSpaces = ' email@example.net ';
- component.email = emailWithSpaces;
-
- const expectedEmail = emailWithSpaces.trim();
-
- // when
- await component.authenticate(eventStub);
-
- // then
- assert.ok(authenticateStub.calledWith(expectedAuthenticator, expectedEmail, sinon.match.any, sinon.match.any));
- });
- });
-});