Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rework account creation flow #1012

Merged
merged 36 commits into from
Dec 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
d59ed85
chore(frontend): add react-hook-form
Falinor Nov 18, 2024
313ce61
feat(frontend): deprecate AppTextInput; create new text input based o…
Falinor Nov 18, 2024
27a331b
feat(frontend): rework the email filling step
Falinor Nov 18, 2024
fc4780a
feat: add SignupLinkDTO
Falinor Nov 18, 2024
f52e827
feat(frontend): add response Image
Falinor Nov 18, 2024
d54f8ce
feat(frontend): rework AccountEmailActivationView
Falinor Nov 18, 2024
752b4bd
feat(frontend): concat multiple errors when using the corresponding form
Falinor Nov 19, 2024
5255e99
feat: add EstablishmentDTO and ProspectDTO
Falinor Nov 19, 2024
fad13c0
refactor(frontend): rework prospect service
Falinor Nov 19, 2024
c70c4fa
test(frontend): add prospect handler for MSW API
Falinor Nov 19, 2024
c11bd01
feat(frontend): rework AccountPasswordCreationView
Falinor Nov 19, 2024
58283f4
feat(frontend): rework AccountAwaitingAccessView
Falinor Nov 19, 2024
301051c
feat(frontend): rework AccountAccessForbiddenView
Falinor Nov 19, 2024
d2df0cd
feat(frontend): replace AccountCampaignIntentCreationView by AccountS…
Falinor Nov 20, 2024
09036d6
feat(server): remove establishment’s campaign intent and priority
Falinor Nov 20, 2024
0b25d1d
refactor(frontend): avoid flash effect when loading a prospect
Falinor Nov 20, 2024
901f795
refactor(frontend): fix wording
Falinor Nov 20, 2024
adec6fa
feat(frontend): remove campaign intent
Falinor Nov 20, 2024
59ec7a4
test(frontend): fix failing tests
Falinor Nov 20, 2024
4cc54cd
test(e2e): test the sign up flow
Falinor Nov 20, 2024
688a814
test(e2e): test the sign up flow failures
Falinor Nov 20, 2024
3a265f2
feat(frontend): add a simplified Header to the guest routes
Falinor Nov 21, 2024
5f465f8
fix(frontend): fix links href
Falinor Nov 21, 2024
5721375
test(frontend): remove the useless Header test
Falinor Nov 21, 2024
2a31419
feat(frontend): treat review comments
Falinor Nov 26, 2024
afd9794
test(frontend): fix failing test
Falinor Nov 26, 2024
2ef9cc6
feat(frontend): remove the last account creation step
Falinor Dec 2, 2024
7f74159
feat(frontend): augment DSFR theme with subtitle1 et 2
Falinor Dec 3, 2024
43419ce
feat(frontend): add hook useIsDsfrReady
Falinor Dec 3, 2024
42376fb
feat(frontend): add an onboarding modal on authenticated pages
Falinor Dec 3, 2024
c775e82
refactor(frontend): remove unused imports
Falinor Dec 3, 2024
ad113bb
test(frontend): fix failing tests
Falinor Dec 4, 2024
6e03db2
feat(frontend): set min password characters to 12
Falinor Dec 4, 2024
f4b3f67
test(frontend): fix failing tests
Falinor Dec 4, 2024
4575366
fix(frontend): increase the onboarding modal’s width
Falinor Dec 9, 2024
6a56424
fix(frontend): revert wrong changes
Falinor Dec 9, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions e2e/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,7 @@ CYPRESS_BASE_URL=https://zerologementvacant-staging.incubateur.net
CYPRESS_API=https://api.zerologementvacant-staging.incubateur.net/api
CYPRESS_EMAIL=E2E_EMAIL
CYPRESS_PASSWORD=E2E_PASSWORD

CYPRESS_MAILER_HOST=https://maildev.zerologementvacant.beta.gouv.fr
CYPRESS_MAILER_USER=
CYPRESS_MAILER_PASSWORD=
33 changes: 33 additions & 0 deletions e2e/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ export interface Config {
baseURL: string;
email: string;
password: string;
mailer: {
host: string;
user: string;
password: string;
};
}

const config = convict<Config>({
Expand All @@ -17,22 +22,50 @@ const config = convict<Config>({
baseURL: {
env: 'CYPRESS_BASE_URL',
doc: 'The base URL of the application',
format: String,
default: null,
nullable: false
},
email: {
env: 'CYPRESS_EMAIL',
doc: 'The email to use for authentication',
format: String,
default: null,
sensitive: true,
nullable: false
},
password: {
env: 'CYPRESS_PASSWORD',
doc: 'The password to use for authentication',
format: String,
default: null,
sensitive: true,
nullable: false
},
mailer: {
host: {
env: 'CYPRESS_MAILER_HOST',
doc: 'The nodemailer host',
format: String,
default: null,
nullable: false
},
user: {
env: 'CYPRESS_MAILER_USER',
doc: 'The nodemailer username',
format: String,
default: null,
sensitive: true,
nullable: false
},
password: {
env: 'CYPRESS_MAILER_PASSWORD',
doc: 'The nodemailer password',
format: String,
default: null,
sensitive: true,
nullable: false
}
}
});

Expand Down
155 changes: 155 additions & 0 deletions e2e/cypress/e2e/sign-up.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
import { faker } from '@faker-js/faker/locale/fr';

describe('Sign up', () => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

top !

it('should sign up', () => {
cy.visit('/connexion');
cy.get('a').contains('Créer votre compte').click();

const user = faker.internet.email();

cy.get('label')
.contains(/Adresse e-mail/i)
.next()
.type(`${user}{enter}`);

cy.location('pathname').should('eq', '/inscription/activation');

// Fetch emails from the Nodemailer API
cy.request({
method: 'GET',
url: `${Cypress.env('MAILER_HOST')}/email`,
auth: {
username: Cypress.env('MAILER_USER'),
password: Cypress.env('MAILER_PASSWORD')
}
}).then((response) => {
const emails: ReadonlyArray<Email> = response.body;
const email: Email = emails
.filter(subject('Activation du compte'))
.filter(to(user))
.filter(unread())
.reduce((acc, email) => (acc.date > email.date ? acc : email));
const link = email.html.substring(
email.html.indexOf('/inscription/mot-de-passe')
);
cy.visit(link);
});

cy.get('label')
.contains(/Définissez votre mot de passe/i)
.next()
.type('123QWEasd');
cy.get('label')
.contains(/Confirmez votre mot de passe/i)
.next()
.type('123QWEasd{enter}');

cy.get('button')
.contains(/Créer mon compte/i)
.click();

cy.location('pathname').should('eq', '/parc-de-logements');
});

it('should await access to LOVAC', () => {
cy.visit('/connexion');
cy.get('a').contains('Créer votre compte').click();

const user = '[email protected]';

cy.get('label')
.contains(/Adresse e-mail/i)
.next()
.type(`${user}{enter}`);

cy.location('pathname').should('eq', '/inscription/activation');

// Fetch emails from the Nodemailer API
cy.request({
method: 'GET',
url: `${Cypress.env('MAILER_HOST')}/email`,
auth: {
username: Cypress.env('MAILER_USER'),
password: Cypress.env('MAILER_PASSWORD')
}
}).then((response) => {
const emails: ReadonlyArray<Email> = response.body;
const email: Email = emails
.filter(subject('Activation du compte'))
.filter(to(user))
.filter(unread())
.reduce((acc, email) => (acc.date > email.date ? acc : email));
const link = email.html.substring(
email.html.indexOf('/inscription/mot-de-passe')
);
cy.visit(link);
});

cy.location('pathname').should('eq', '/inscription/en-attente');
});

it('should forbid access to unauthorized users', () => {
cy.visit('/connexion');
cy.get('a').contains('Créer votre compte').click();

const user = '[email protected]';

cy.get('label')
.contains(/Adresse e-mail/i)
.next()
.type(`${user}{enter}`);

cy.location('pathname').should('eq', '/inscription/activation');

// Fetch emails from the Nodemailer API
cy.request({
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍👍

method: 'GET',
url: `${Cypress.env('MAILER_HOST')}/email`,
auth: {
username: Cypress.env('MAILER_USER'),
password: Cypress.env('MAILER_PASSWORD')
}
}).then((response) => {
const emails: ReadonlyArray<Email> = response.body;
const email: Email = emails
.filter(subject('Activation du compte'))
.filter(to(user))
.filter(unread())
.reduce((acc, email) => (acc.date > email.date ? acc : email));
const link = email.html.substring(
email.html.indexOf('/inscription/mot-de-passe')
);
cy.visit(link);
});

cy.location('pathname').should('eq', '/inscription/impossible');
});
});

interface Email {
id: string;
html: string;
subject: string;
from: ReadonlyArray<{
address: string;
name: string;
}>;
to: ReadonlyArray<{
address: string;
name: string;
}>;
date: string;
read: boolean;
}

function subject(subject: string) {
return (email: Email) => email.subject === subject;
}

function to(recipient: string) {
return (email: Email) => email.to.some((to) => to.address === recipient);
}

function unread() {
return (email: Email) => !email.read;
}
1 change: 1 addition & 0 deletions e2e/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
},
"devDependencies": {
"@dotenvx/dotenvx": "^1.14.2",
"@faker-js/faker": "^8.4.1",
"@types/convict": "^6.1.6",
"convict": "^6.2.4",
"cypress": "^13.15.0",
Expand Down
14 changes: 14 additions & 0 deletions frontend/jest.polyfills.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,17 @@ Object.defineProperties(globalThis, {
Request: { value: Request, configurable: true },
Response: { value: Response, configurable: true }
});

Object.defineProperty(window, 'matchMedia', {
writable: true,
value: (query) => ({
matches: false,
media: query,
onchange: null,
addListener: jest.fn(), // Deprecated
removeListener: jest.fn(), // Deprecated
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
dispatchEvent: jest.fn()
})
});
2 changes: 2 additions & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"@codegouvfr/react-dsfr": "1.9.16",
"@emotion/react": "^11.13.3",
"@emotion/styled": "^11.13.0",
"@hookform/resolvers": "^3.9.1",
"@jonkoops/matomo-tracker-react": "^0.7.0",
"@lexical/html": "^0.18.0",
"@lexical/list": "^0.18.0",
Expand Down Expand Up @@ -55,6 +56,7 @@
"qs": "^6.13.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-hook-form": "^7.53.2",
"react-map-gl": "^7.1.7",
"react-redux": "^8.1.3",
"react-redux-loading-bar": "^5.0.8",
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import ForgottenPasswordView from './views/Account/ForgottenPasswordView';
import ResetPasswordView from './views/Account/ResetPasswordView';
import NotFoundView from './views/NotFoundView';
import AnalysisView from './views/Analysis/AnalysisView';
import { useIsDsfrReady } from './hooks/useIsDsfrReady';

const router = createBrowserRouter(
createRoutesFromElements(
Expand Down Expand Up @@ -92,6 +93,8 @@ function App() {
)
);

useIsDsfrReady();

useEffect(() => {
if (isSomeQueryPending) {
dispatch(showLoading());
Expand Down
21 changes: 21 additions & 0 deletions frontend/src/assets/images/community.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading