Skip to content

Commit b01c270

Browse files
Unknown error component + full tests
1 parent df32557 commit b01c270

16 files changed

Lines changed: 319 additions & 16 deletions

docs/ARCHITECTURE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@
114114
┣ 🖼️assets
115115
┃ ┣ ⚙️_config
116116
┃ ┣ 💾_data
117+
┃ ┣ 🎬animations
117118
┃ ┣ 🌄background
118119
┃ ┣ 🔡fonts
119120
┃ ┣ 🗣️i18n

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@
100100
"@fortawesome/free-brands-svg-icons": "7.1.0",
101101
"@fortawesome/free-regular-svg-icons": "7.1.0",
102102
"@fortawesome/free-solid-svg-icons": "7.1.0",
103+
"@lottiefiles/dotlottie-wc": "0.9.8",
103104
"@ngx-translate/core": "17.0.0",
104105
"@ngx-translate/http-loader": "17.0.0",
105106
"rxjs": "7.8.2",

pnpm-lock.yaml

Lines changed: 58 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/app/core/_config/team/developers.constant.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ export const TEAM_DEVELOPERS: Developer[] = [
2929
id: 5,
3030
name: 'Jason Parse',
3131
photoUrl: 'https://api.dicebear.com/9.x/fun-emoji/svg?seed=JasonParse&backgroundColor=b6e3f4',
32-
photoScale: 0.9,
33-
photoTranslateY: '7px',
32+
photoScale: 1.1,
33+
photoTranslateY: '0px',
3434
apologizesMessage: 'PAGES.ERROR.SERVER.APOLOGIZES.DEV.3'
3535
}
3636
];

src/app/shared/error-handler/error-handler.component.html

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@ <h1 class="error-view__title">
33
{{ 'PAGES.ERROR.NOT_FOUND.TITLE' | translate }}
44
</h1>
55

6-
<h3
7-
class="error-view__code"
8-
[class.is-english]="translate.getCurrentLang() === 'en'">
9-
<span class="error-view__label">{{ 'PAGES.ERROR.NOT_FOUND.LABEL' | translate }}</span>
10-
<span class="error-view__code-value">{{ code() }}</span>
11-
</h3>
6+
@if (code()) {
7+
<h3
8+
class="error-view__code"
9+
[class.is-english]="translate.getCurrentLang() === 'en'">
10+
<span class="error-view__label">{{ 'PAGES.ERROR.NOT_FOUND.LABEL' | translate }}</span>
11+
<span class="error-view__code-value">{{ code() }}</span>
12+
</h3>
13+
}
1214

1315
<div class="error-view__content">
1416
<router-outlet />

src/app/shared/error-handler/error-handler.component.spec.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,10 +335,46 @@ describe('ErrorHandlerComponent', () => {
335335
expect(buttonDebugEl.componentInstance.label()).toBe('Se connecter');
336336
expect(router.navigate).toHaveBeenCalledWith(['/login']);
337337
});
338+
339+
it('should NOT render the error code block when code is empty (unknown error)', () => {
340+
// --- ARRANGE ---
341+
Object.defineProperty(router, 'url', { value: '/error/unknown-error', configurable: true });
342+
queryParams$.next({});
343+
344+
// --- ACT ---
345+
fixture.detectChanges();
346+
347+
// --- ASSERT ---
348+
expect(component.code()).toBe('');
349+
350+
const codeContainer = fixture.debugElement.query(By.css('.error-view__code'));
351+
352+
expect(codeContainer).toBeNull();
353+
});
354+
355+
it('should render the error code block when code is provided', () => {
356+
// --- ARRANGE ---
357+
Object.defineProperty(router, 'url', { value: '/error/unfound-error', configurable: true });
358+
queryParams$.next({ code: '404' });
359+
360+
// --- ACT ---
361+
fixture.detectChanges();
362+
363+
// --- ASSERT ---
364+
expect(component.code()).toBe('404');
365+
366+
const codeContainer = fixture.debugElement.query(By.css('.error-view__code'));
367+
368+
expect(codeContainer).toBeTruthy();
369+
expect(codeContainer.nativeElement.textContent).toContain('404');
370+
});
338371
});
339372

340373
describe('Internationalization (i18n)', () => {
341374
it('should display the default French translations on init', () => {
375+
// --- ARRANGE ---
376+
queryParams$.next({ code: '404' });
377+
342378
// --- ACT ---
343379
fixture.detectChanges();
344380

@@ -352,6 +388,7 @@ describe('ErrorHandlerComponent', () => {
352388

353389
it('should update static texts when language is switched to English', () => {
354390
// --- ARRANGE ---
391+
queryParams$.next({ code: '404' });
355392
fixture.detectChanges();
356393

357394
// --- ACT ---
@@ -409,6 +446,9 @@ describe('ErrorHandlerComponent', () => {
409446
});
410447

411448
it('should apply "is-english" class to the code container when language is English', () => {
449+
// --- ARRANGE ---
450+
queryParams$.next({ code: '404' });
451+
412452
// --- ACT ---
413453
translate.use('en');
414454
fixture.detectChanges();
@@ -420,6 +460,9 @@ describe('ErrorHandlerComponent', () => {
420460
});
421461

422462
it('should NOT apply "is-english" class when language is French', () => {
463+
// --- ARRANGE ---
464+
queryParams$.next({ code: '404' });
465+
423466
// --- ACT ---
424467
translate.use('fr');
425468
fixture.detectChanges();
Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,21 @@
1-
<p>Hello World unknown-error works!</p>
1+
<section class="unknown-error">
2+
<div class="unknown-error__content">
3+
<div class="unknown-error__animation-wrapper">
4+
<dotlottie-wc
5+
src="assets/animations/unknown-error-abduction.lottie"
6+
autoplay
7+
loop
8+
role="img"
9+
[attr.aria-label]="'PAGES.ERROR.UNKNOWN.IMG.ALT.ABDUCTION' | translate"
10+
class="unknown-error__lottie" />
11+
</div>
12+
13+
<h4 class="unknown-error__title">
14+
{{ 'PAGES.ERROR.UNKNOWN.TITLE' | translate }}
15+
</h4>
16+
17+
<h5 class="unknown-error__subtitle">
18+
{{ 'PAGES.ERROR.UNKNOWN.SUBTITLE' | translate }}
19+
</h5>
20+
</div>
21+
</section>
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,52 @@
1+
@use 'abstracts' as *;
2+
13
:host {
24
display: block;
35
}
6+
7+
.unknown-error {
8+
display: flex;
9+
align-items: center;
10+
justify-content: center;
11+
text-align: center;
12+
background-color: var(--bg-color);
13+
14+
&__content {
15+
display: flex;
16+
flex-direction: column;
17+
align-items: center;
18+
gap: 1rem;
19+
width: 100%;
20+
max-width: 600px;
21+
}
22+
23+
&__animation-wrapper {
24+
width: 100%;
25+
max-width: 300px;
26+
margin: 0 auto;
27+
animation: float 6s ease-in-out infinite;
28+
}
29+
30+
&__lottie {
31+
display: block;
32+
aspect-ratio: 1 / 1;
33+
width: 100%;
34+
height: auto;
35+
border-radius: 16px;
36+
border: solid 2px var(--primary-color);
37+
overflow: hidden;
38+
}
39+
40+
&__title {
41+
color: var(--primary-color);
42+
margin: 0;
43+
}
44+
45+
&__subtitle {
46+
color: transparent;
47+
margin: 0;
48+
background: linear-gradient(to right, var(--secondary-color), var(--primary-color));
49+
-webkit-background-clip: text;
50+
background-clip: text;
51+
}
52+
}

0 commit comments

Comments
 (0)