This commit is contained in:
pro.boooooo 2024-04-03 03:46:05 +02:00
parent 7402661aaa
commit 873dd8c458
25 changed files with 404 additions and 129 deletions

View File

@ -17,6 +17,7 @@
}, },
"dependencies": { "dependencies": {
"axios": "^1.6.7", "axios": "^1.6.7",
"clipboard-copy": "^4.0.1",
"react": "^18.2.0", "react": "^18.2.0",
"react-apexcharts": "^1.4.1", "react-apexcharts": "^1.4.1",
"react-chartjs-2": "^5.2.0", "react-chartjs-2": "^5.2.0",

View File

@ -37,36 +37,6 @@ export default defineConfig({
name: "chromium", name: "chromium",
use: { ...devices["Desktop Chrome"] }, use: { ...devices["Desktop Chrome"] },
}, },
// {
// name: "firefox",
// use: { ...devices["Desktop Firefox"] },
// },
// {
// name: "webkit",
// use: { ...devices["Desktop Safari"] },
// },
/* Test against mobile viewports. */
// {
// name: 'Mobile Chrome',
// use: { ...devices['Pixel 5'] },
// },
// {
// name: 'Mobile Safari',
// use: { ...devices['iPhone 12'] },
// },
/* Test against branded browsers. */
// {
// name: 'Microsoft Edge',
// use: { ...devices['Desktop Edge'], channel: 'msedge' },
// },
// {
// name: 'Google Chrome',
// use: { ...devices['Desktop Chrome'], channel: 'chrome' },
// },
], ],
//Run your local dev server before starting the tests / //Run your local dev server before starting the tests /

7
pnpm-lock.yaml generated
View File

@ -8,6 +8,9 @@ dependencies:
axios: axios:
specifier: ^1.6.7 specifier: ^1.6.7
version: 1.6.8 version: 1.6.8
clipboard-copy:
specifier: ^4.0.1
version: 4.0.1
react: react:
specifier: ^18.2.0 specifier: ^18.2.0
version: 18.2.0 version: 18.2.0
@ -1143,6 +1146,10 @@ packages:
string-width: 7.1.0 string-width: 7.1.0
dev: true dev: true
/clipboard-copy@4.0.1:
resolution: {integrity: sha512-wOlqdqziE/NNTUJsfSgXmBMIrYmfd5V0HCGsR8uAKHcg+h9NENWINcfRjtWGU77wDHC8B8ijV4hMTGYbrKovng==}
dev: false
/color-convert@1.9.3: /color-convert@1.9.3:
resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
dependencies: dependencies:

View File

@ -3,7 +3,6 @@ import axios from "axios";
export const isLoggedIn = async () => { export const isLoggedIn = async () => {
try { try {
const response = await axios.get("/authenticate"); const response = await axios.get("/authenticate");
return response.data; return response.data;
} catch (error) { } catch (error) {
return error.response.data; return error.response.data;

View File

@ -1,6 +1,7 @@
import axios from "axios"; import axios from "axios";
export const createItem = async (settings) => { export const createItem = async (settings) => {
try {
console.log(settings); console.log(settings);
const formData = new FormData(); const formData = new FormData();
@ -17,9 +18,14 @@ export const createItem = async (settings) => {
const response = await axios.post("/item", formData); const response = await axios.post("/item", formData);
return response.data; return response.data;
} catch (err) {
console.error(err);
return null;
}
}; };
export const updateItem = async (settings) => { export const updateItem = async (settings) => {
try {
console.log(settings); console.log(settings);
const formData = new FormData(); const formData = new FormData();
@ -32,10 +38,19 @@ export const updateItem = async (settings) => {
const response = await axios.put(`/item/${settings._id}`, formData); const response = await axios.put(`/item/${settings._id}`, formData);
return response.data; return response.data;
} catch (err) {
console.error(err);
return null;
}
}; };
export const deleteItem = async (id) => { export const deleteItem = async (id) => {
try {
console.log(id); console.log(id);
const response = await axios.delete(`/item/${id}`); const response = await axios.delete(`/item/${id}`);
return response.data; return response.data;
} catch (err) {
console.error(err);
return null;
}
}; };

View File

@ -1,10 +1,76 @@
import axios from "axios"; import axios from "axios";
import { createItem } from "./items";
export const importRooms = async (data) => {
try {
const parsed = JSON.parse(data);
if (parsed.length === 0) {
return false;
}
for (let e of parsed) {
const room = await createRoom(e.name);
for (let f of e.items) {
const settings = { ...f, room: room._id };
await createItem(settings);
}
}
return true;
} catch (err) {
console.error(err);
return null;
}
};
export const exportRooms = async () => {
try {
const rooms = await getRooms();
let stock = [];
for (let room of rooms) {
const roomData = await getRoom(room._id);
delete roomData._id;
delete roomData.__v;
delete roomData.user;
delete roomData.updatedAt;
delete roomData.createdAt;
await roomData.items.forEach((f) => {
delete f.createdAt;
delete f.image;
delete f.invoice;
delete f.updatedAt;
delete f.room;
delete f.user;
delete f.__v;
delete f._id;
});
stock.push(roomData);
}
const final = JSON.stringify(stock);
return final;
} catch (err) {
console.error(err);
return null;
}
};
export const createRoom = async (name) => { export const createRoom = async (name) => {
try {
const response = await axios.post("/room", { const response = await axios.post("/room", {
name, name,
}); });
return response.data; return response.data;
} catch (err) {
console.error(err);
}
}; };
export const getState = async () => { export const getState = async () => {
@ -18,16 +84,31 @@ export const getState = async () => {
}; };
export const deleteRoom = async (id) => { export const deleteRoom = async (id) => {
try {
const response = await axios.delete(`/room/${id}`); const response = await axios.delete(`/room/${id}`);
return response.data; return response.data;
} catch (err) {
console.error(err);
return null;
}
}; };
export const getRooms = async () => { export const getRooms = async () => {
try {
const response = await axios.get(`/room`); const response = await axios.get(`/room`);
return response.data; return response.data;
} catch (err) {
console.error(err);
return null;
}
}; };
export const getRoom = async (id) => { export const getRoom = async (id) => {
try {
const response = await axios.get(`/room/${id}`); const response = await axios.get(`/room/${id}`);
return response.data; return response.data;
} catch (err) {
console.error(err);
return null;
}
}; };

View File

@ -18,8 +18,9 @@ export const createUser = async (username, password, confirmation) => {
confirmation, confirmation,
}); });
return response.data; return response.data;
} catch (error) { } catch (err) {
return error.response.data; console.error(err);
return null;
} }
}; };

View File

@ -3,6 +3,11 @@
* { * {
margin: 0; margin: 0;
padding: 0; padding: 0;
::selection {
background: $primary;
color: white;
}
} }
body { body {
a { a {

View File

@ -1,9 +1,9 @@
import { MagnifyingGlass } from "react-loader-spinner"; import { MagnifyingGlass } from "react-loader-spinner";
import "./LoaderSpace.scss"; import "./LoaderSpace.scss";
export default function LoaderSpace({ isVisible }) { export default function LoaderSpace({ isVisible, isCenterLoader }) {
return ( return (
<div className="loader-space-container"> <div className={`loader-space-container${isCenterLoader ? "-center" : ""}`}>
<MagnifyingGlass <MagnifyingGlass
visible={isVisible} visible={isVisible}
height="100" height="100"

View File

@ -1,4 +1,4 @@
.loader-space-container { .loader-space-container-center {
position: absolute; position: absolute;
z-index: 9999; z-index: 9999;
position: fixed; position: fixed;
@ -6,3 +6,6 @@
left: 50%; left: 50%;
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
} }
.loader-space-container {
}

View File

@ -16,9 +16,9 @@ const initState = {
export const AuthenticationContext = React.createContext({ export const AuthenticationContext = React.createContext({
...initState, ...initState,
login: () => {}, login: async () => {},
register: () => {}, register: () => {},
logout: () => {}, logout: async () => {},
}); });
export const AuthenticationProvider = ({ children }) => { export const AuthenticationProvider = ({ children }) => {
@ -46,6 +46,7 @@ export const AuthenticationProvider = ({ children }) => {
const register = async (username, password, confirmation) => { const register = async (username, password, confirmation) => {
try { try {
const user = await registerApi(username, password, confirmation); const user = await registerApi(username, password, confirmation);
console.log(user);
setAuthState({ user }); setAuthState({ user });
redirect(); redirect();
} catch (error) { } catch (error) {

View File

@ -1,5 +1,5 @@
import NavBar from "../components/NavBar/NavBar"; import NavBar from "../components/NavBar/NavBar";
import "./Layout.css"; import "./Layout.scss";
export default function Layout({ children }) { export default function Layout({ children }) {
return ( return (

View File

@ -1,4 +1,5 @@
#layout-container { #layout-container {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
margin-bottom: 20px;
} }

View File

@ -0,0 +1,38 @@
@import "../../assets/styles/vars.scss";
.container {
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
width: 100%;
height: 100%;
gap: 20px;
margin-top: 30px;
.title {
color: $good_black;
}
.error {
color: red;
font-weight: bold;
}
.form {
display: flex;
flex-direction: column;
justify-content: space-around;
align-items: center;
border-radius: $my_border_rad;
border: 1px dashed $good_black;
gap: 10px;
padding: 10px;
.ipt {
width: 300px;
height: 35px;
text-align: center;
}
}
}

View File

@ -1,6 +1,8 @@
import React, { useState } from "react"; import React, { useState } from "react";
import { useAuth } from "../../hooks"; import { useAuth } from "../../hooks";
import { useEffect } from "react"; import { useEffect } from "react";
import "./authanticated.scss";
import "../../components/StylizedBtn/StylizedBtn.scss";
export const Login = () => { export const Login = () => {
const { login } = useAuth(); const { login } = useAuth();
@ -18,32 +20,36 @@ export const Login = () => {
const response = await login(username, password); const response = await login(username, password);
if (response && !response.success) { if (response && !response.success) {
console.log("salut");
setError(response.error); setError(response.error);
} }
}; };
return ( return (
<div> <div className="container">
<h1>Login page</h1> <form className="form" onSubmit={onSubmit}>
{error && <p className="text-red-500">{error}</p>} <h3 className="title">Connexion</h3>
{error && <p>{error}</p>}
<form onSubmit={onSubmit}>
<input <input
type="text" type="text"
value={username} value={username}
placeholder="username" placeholder="Pseudo"
className="ipt"
required required
onChange={(e) => setUsername(e.target.value)} onChange={(e) => setUsername(e.target.value)}
/> />
<input <input
type="password" type="password"
value={password} value={password}
placeholder="password" placeholder="Mot de passe"
className="ipt"
required required
onChange={(e) => setPassword(e.target.value)} onChange={(e) => setPassword(e.target.value)}
/> />
<button type="submit">submit</button>
<button className="stylized-btn" type="submit">
Go
</button>
</form> </form>
</div> </div>
); );

View File

@ -1,5 +1,5 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect } from "react";
import "../../components/StylizedBtn/StylizedBtn.scss";
import { useAuth } from "../../hooks"; import { useAuth } from "../../hooks";
export const Register = () => { export const Register = () => {
@ -8,49 +8,69 @@ export const Register = () => {
const [username, setUsername] = useState(""); const [username, setUsername] = useState("");
const [password, setPassword] = useState(""); const [password, setPassword] = useState("");
const [confirmation, setConfirmation] = useState(""); const [confirmation, setConfirmation] = useState("");
const [error, setError] = useState(); const [error, setError] = useState(null);
useEffect(() => { useEffect(() => {
document.title = "Inscription"; document.title = "Inscription";
}, []); }, []);
const onSubmit = async (e) => { const onSubmit = async (e) => {
try {
e.preventDefault(); e.preventDefault();
const response = await register(username, password, confirmation); const response = await register(username, password, confirmation);
console.log(response);
if (!response) {
setError(
"Assurez vous que le mot de passe contient au moins 8 caracteres dont une majuscule, un symbole special et au minimum un chiffre.",
);
}
if (response && !response.success) { if (response && !response.success) {
setError(response.error); setError(
"Assurez vous que le mot de passe contient au moins 8 caracteres dont une majuscule, un symbole special et au minimum un chiffre.",
);
}
} catch (err) {
console.error(err);
} }
}; };
return ( return (
<div> <div className="container">
<h1>Register page</h1> <form className="form" onSubmit={onSubmit}>
{error && <p className="text-red-500">{error}</p>} <h3 className="title">Inscription</h3>
<form onSubmit={onSubmit}>
{error ? <div className="error">{error}</div> : null}
<input <input
type="text" type="text"
value={username} value={username}
placeholder="username" placeholder="Pseudo"
className="ipt"
required required
onChange={(e) => setUsername(e.target.value)} onChange={(e) => setUsername(e.target.value)}
/> />
<input <input
type="password" type="password"
className="ipt"
value={password} value={password}
required required
placeholder="password" min={8}
placeholder="Mot de passe"
onChange={(e) => setPassword(e.target.value)} onChange={(e) => setPassword(e.target.value)}
/> />
<input <input
type="password" type="password"
className="ipt"
min={8}
required required
value={confirmation} value={confirmation}
placeholder="confirmation" placeholder="Confirmation du mot de passe"
onChange={(e) => setConfirmation(e.target.value)} onChange={(e) => setConfirmation(e.target.value)}
/> />
<button type="submit">submit</button> <button className="stylized-btn" type="submit">
Go
</button>
</form> </form>
</div> </div>
); );

View File

@ -85,7 +85,7 @@ export const Home = () => {
</div> </div>
)} )}
<LoaderSpace isVisible={isLoad} /> <LoaderSpace isVisible={isLoad} isCenterLoader={true} />
{dataset ? ( {dataset ? (
<div id="stats-container"> <div id="stats-container">

View File

@ -1,9 +1,17 @@
import { useAuth } from "../../hooks"; import { useAuth } from "../../hooks";
import { useState, useEffect } from "react"; import { useState, useEffect } from "react";
import "./Profile.scss"; import "./Profile.scss";
import { updateUser, deleteUser, logout } from "../../api"; import {
updateUser,
deleteUser,
logout,
exportRooms,
importRooms,
} from "../../api";
import StylizedBtn from "../../components/StylizedBtn/StylizedBtn"; import StylizedBtn from "../../components/StylizedBtn/StylizedBtn";
import passwordCheck from "../../services/password"; import passwordCheck from "../../services/password";
import LoaderSpace from "./../../components/LoaderSpace/LoaderSpace";
import clipboardCopy from "clipboard-copy";
//Bilouuuuuuu94!@@ //Bilouuuuuuu94!@@
export default function Profile() { export default function Profile() {
@ -13,6 +21,10 @@ export default function Profile() {
const [oldPPassword, setOldPPassword] = useState(""); const [oldPPassword, setOldPPassword] = useState("");
const [password, setPassword] = useState(""); const [password, setPassword] = useState("");
const [confirmPassword, setConfirmPassword] = useState(""); const [confirmPassword, setConfirmPassword] = useState("");
const [isIELoad, setIsIELoad] = useState(false);
const [exportDatas, setExportDatas] = useState(null);
const [importMsg, setImportMsg] = useState("");
const [isInAfterImport, setIsInAfterImport] = useState(false);
useEffect(() => { useEffect(() => {
document.title = `Profile`; document.title = `Profile`;
@ -40,6 +52,37 @@ export default function Profile() {
setOldPPassword(e.target.value); setOldPPassword(e.target.value);
}; };
const importData = () => {
const data = prompt("Veuillez coller le code que vous avez copier");
if (!data) return;
setExportDatas(null);
setIsInAfterImport(true);
setIsIELoad(true);
setImportMsg("Chargement ...");
importRooms(data).then((res) => {
if (!res) {
setImportMsg("Une erreur est survenue");
} else {
setImportMsg("Vos depenses ont ete transfere avec sucess.");
}
setIsIELoad(false);
console.log(res);
});
};
const exportData = () => {
setIsIELoad(true);
setIsInAfterImport(false);
exportRooms().then((res) => {
setExportDatas(res);
setIsIELoad(false);
clipboardCopy(`${res}`).then();
});
};
const handleSubmitPassword = () => { const handleSubmitPassword = () => {
if (!passwordCheck(password, confirmPassword)) { if (!passwordCheck(password, confirmPassword)) {
alert( alert(
@ -148,18 +191,36 @@ export default function Profile() {
<div className="profile-modifier-container"> <div className="profile-modifier-container">
<span onClick={handleHelpIE} className="profile-modifier-title "> <span onClick={handleHelpIE} className="profile-modifier-title ">
Fais voyager tes depenses. Fais voyager tes depenses !
</span> </span>
<LoaderSpace isCenterLoader={false} isVisible={isIELoad} />
{exportDatas ? (
<div id="exported-datas-container">
<div id="exported-datas-tips">
Vos données ont été copiées dans le presse-papier. Pour pouvoir
les importer, il suffira juste de cliquer sur le bouton ci-dessous{" "}
<b>"Importer"</b>, puis de coller les données dans le champ de
saisie qui s'ouvrira en haut de l'écran.
</div>
<div id="exported-datas">{exportDatas}</div>
</div>
) : null}
{isInAfterImport ? <div>{importMsg}</div> : null}
{!exportDatas ? (
<StylizedBtn <StylizedBtn
perso_style={{ width: "100px" }} perso_style={{ width: "100px" }}
handle={null} handle={exportData}
text="Exporter" text="Exporter"
/> />
) : null}
<StylizedBtn <StylizedBtn
perso_style={{ width: "100px" }} perso_style={{ width: "100px" }}
handle={null} handle={importData}
text="Importer" text="Importer"
/> />
</div> </div>

View File

@ -33,11 +33,31 @@
gap: 10px; gap: 10px;
border-radius: $my_border_rad; border-radius: $my_border_rad;
#exported-datas-container {
width: 80%;
max-height: 300px;
display: flex;
flex-direction: column;
gap: 20px;
#exported-datas-tips {
border: 1px solid $good_black;
padding: 5px;
}
#exported-datas {
width: 100%;
max-height: 200px;
overflow: auto;
}
}
@media (max-width: 770px) { @media (max-width: 770px) {
width: 80%; width: 80%;
} }
.profile-modifier-title { .profile-modifier-title {
cursor: pointer;
color: $black_text; color: $black_text;
font-weight: bold; font-weight: bold;
} }

View File

@ -5,6 +5,7 @@ import "./Room.scss";
import AddBtn from "../../components/AddBtn/AddBtn"; import AddBtn from "../../components/AddBtn/AddBtn";
import { createItem, deleteItem, updateItem } from "../../api/"; import { createItem, deleteItem, updateItem } from "../../api/";
import StylizedBtn from "../../components/StylizedBtn/StylizedBtn"; import StylizedBtn from "../../components/StylizedBtn/StylizedBtn";
import LoaderSpace from "../../components/LoaderSpace/LoaderSpace";
export default function Room() { export default function Room() {
const { id } = useParams(); const { id } = useParams();
@ -12,12 +13,16 @@ export default function Room() {
const [isInForm, setInForm] = useState(false); const [isInForm, setInForm] = useState(false);
const [isInFormUpdate, setIsInFormUpdate] = useState(false); const [isInFormUpdate, setIsInFormUpdate] = useState(false);
const [formUpdateData, setFormUpdateData] = useState(null); const [formUpdateData, setFormUpdateData] = useState(null);
const [isLoading, setIsLoading] = useState(false);
useEffect(() => { useEffect(() => {
setIsLoading(true);
getRoom(id).then((res) => { getRoom(id).then((res) => {
console.log(res); console.log(res);
document.title = `Piece - ${res.name}`; document.title = `Piece - ${res.name}`;
setData(res); setData(res);
setIsLoading(false);
}); });
}, []); }, []);
@ -109,6 +114,10 @@ export default function Room() {
</div> </div>
) : null} ) : null}
{isLoading ? (
<LoaderSpace isCenterLoader={true} isVisible={isLoading} />
) : null}
{isInForm || isInFormUpdate ? <div id="blur"></div> : null} {isInForm || isInFormUpdate ? <div id="blur"></div> : null}
{data.items && data.items.length > 0 ? ( {data.items && data.items.length > 0 ? (
@ -176,11 +185,7 @@ export default function Room() {
</div> </div>
))} ))}
</div> </div>
) : ( ) : null}
<div>
<span>Cette piece ne contient pas d'objet.</span>
</div>
)}
{isInForm && ( {isInForm && (
<div id="form-container"> <div id="form-container">

View File

@ -106,6 +106,7 @@
display: flex; display: flex;
gap: 5px; gap: 5px;
width: 100%; width: 100%;
align-items: center;
.item-description { .item-description {
color: $black; color: $black;
@ -117,6 +118,7 @@
display: flex; display: flex;
width: 100%; width: 100%;
gap: 5px; gap: 5px;
align-items: center;
.item-price { .item-price {
font-weight: bold; font-weight: bold;
@ -126,6 +128,7 @@
.item-buy-date-container { .item-buy-date-container {
display: flex; display: flex;
width: 100%; width: 100%;
align-items: center;
gap: 5px; gap: 5px;
.item-buy-date { .item-buy-date {

View File

@ -3,6 +3,7 @@ import { useState, useEffect } from "react";
import { createRoom, getRooms, deleteRoom } from "../../api"; import { createRoom, getRooms, deleteRoom } from "../../api";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import LoaderSpace from "../../components/LoaderSpace/LoaderSpace"; import LoaderSpace from "../../components/LoaderSpace/LoaderSpace";
import AddBtn from "./../../components/AddBtn/AddBtn";
export default function Rooms() { export default function Rooms() {
const [rooms, setRooms] = useState(null); const [rooms, setRooms] = useState(null);
@ -85,7 +86,7 @@ export default function Rooms() {
))} ))}
</div> </div>
) : ( ) : (
<LoaderSpace isVisible={isLoad} /> <LoaderSpace isVisible={isLoad} isCenterLoader={true} />
)} )}
{isErr && !isLoad ? ( {isErr && !isLoad ? (
@ -94,9 +95,7 @@ export default function Rooms() {
<div id="rooms-add-container"> <div id="rooms-add-container">
<div id="rooms-text-on">Creer une nouvelle piece</div> <div id="rooms-text-on">Creer une nouvelle piece</div>
<button id="add-rooms" onClick={onClickCreate}> <AddBtn handle={onClickCreate} />
+
</button>
</div> </div>
</div> </div>
); );

BIN
sujet.pdf Normal file

Binary file not shown.

View File

@ -1,26 +1,32 @@
// @ts-check // @ts-check
import { test, expect } from "@playwright/test"; import { test, expect } from "@playwright/test";
import { waitFor } from "@testing-library/react";
test("Test de connexion", async ({ page }) => { test("Test de connexion", async ({ page }) => {
const account = "Bilouuuuuuu94!@@";
await page.goto("/login"); await page.goto("/login");
await page.waitForURL("/login");
await page await page
.locator( .locator(
"#layout-container > main > div > form > input[type=text]:nth-child(1)", "#layout-container > main > div > form > input[type=text]:nth-child(1)",
) )
.fill("Bilouuuuuuu94!@@"); .fill(account);
await page await page
.locator( .locator(
"#layout-container > main > div > form > input[type=password]:nth-child(2)", "#layout-container > main > div > form > input[type=password]:nth-child(2)",
) )
.fill("Bilouuuuuuu94!@@"); .fill(account);
await page.locator("#layout-container > main > div > form > button").click({ await page.locator("#layout-container > main > div > form > button").click({
button: "left", button: "left",
}); });
await page.waitForURL("/"); await page.waitForURL("/");
const title = await page.title();
console.log(title); expect(await page.title()).toBe("Accueil");
expect(await page.locator("#title").innerText()).toBe(`Bonjour ${account} !`);
test.setTimeout(10000);
await page.waitForURL("/");
}); });

View File

@ -0,0 +1,33 @@
// @ts-check
import { test, expect } from "@playwright/test";
test("Test de connexion", async ({ page }) => {
const account = "Eheheh9400$$!@@";
await page.goto("/register");
await page.waitForURL("/register");
await page
.locator(
"#layout-container > main > div > form > input[type=text]:nth-child(1)",
)
.fill(account);
await page
.locator(
"#layout-container > main > div > form > input[type=password]:nth-child(2)",
)
.fill(account);
await page
.locator(
"#layout-container > main > div > form > input[type=password]:nth-child(3)",
)
.fill(account);
await page
.locator("#layout-container > main > div > form > button")
.click({ button: "left" });
await page.waitForURL("/");
expect(await page.title()).toBe("Accueil");
expect(await page.locator("#title").innerText()).toBe(`Bonjour ${account} !`);
});