feat: bringing it all together
This is now showing the MainMenu on the profile page which in turn pulls in the Settings modal. I wasn't able to register the modal on Storybook yet, which means that there won't be any on the Profile template or page story. The implementation in Skeleton is causing some accessibility warnings. However, since there next version is taking a radical different approach I'm inclined to let it be for now. We should document it somewhere, I guess. Signed-off-by: André Jaenisch <andre.jaenisch@posteo.de>
This commit is contained in:
parent
581ab76ca7
commit
f20587cf1f
12 changed files with 639 additions and 259 deletions
|
@ -12,33 +12,19 @@ You should have received a copy of the GNU Affero General Public License along w
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {
|
import { AppRail, AppRailAnchor, AppRailTile } from '@skeletonlabs/skeleton';
|
||||||
AppRail,
|
import { createEventDispatcher } from 'svelte';
|
||||||
AppRailAnchor,
|
|
||||||
AppRailTile,
|
|
||||||
Drawer,
|
|
||||||
getDrawerStore
|
|
||||||
} from '@skeletonlabs/skeleton';
|
|
||||||
import { _, locale, locales } from 'svelte-i18n';
|
import { _, locale, locales } from 'svelte-i18n';
|
||||||
import { Bell24, Gear24, Key24, Paintbrush24, Person24 } from 'svelte-octicons';
|
import { Bell24, Gear24, Key24, Paintbrush24, Person24 } from 'svelte-octicons';
|
||||||
|
|
||||||
let currentTile = 0;
|
let currentTile = 0;
|
||||||
const drawerStore = getDrawerStore();
|
const dispatcher = createEventDispatcher();
|
||||||
|
|
||||||
function onTileChanged(ev) {
|
function onTileChanged(ev) {
|
||||||
const settings = { id: ev.target.value };
|
dispatcher('switch-settings', ev.target.value);
|
||||||
drawerStore.open(settings);
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Drawer>
|
|
||||||
{#if $drawerStore.id === 'profile'}
|
|
||||||
<b>Profile settings go here</b>
|
|
||||||
{:else}
|
|
||||||
{$drawerStore.id}
|
|
||||||
{/if}
|
|
||||||
</Drawer>
|
|
||||||
|
|
||||||
<AppRail aspectRatio="auto" gap="gap-8" height="h-auto" width="w-[230px]" spacing="my-2">
|
<AppRail aspectRatio="auto" gap="gap-8" height="h-auto" width="w-[230px]" spacing="my-2">
|
||||||
<svelte:fragment slot="lead">
|
<svelte:fragment slot="lead">
|
||||||
<AppRailTile
|
<AppRailTile
|
||||||
|
|
|
@ -42,7 +42,8 @@ You should have received a copy of the GNU Affero General Public License along w
|
||||||
<div class="flex flex-col bg-white border-surface-300 rounded-border px-4">
|
<div class="flex flex-col bg-white border-surface-300 rounded-border px-4">
|
||||||
<div class="flex gap-4 bg-white">
|
<div class="flex gap-4 bg-white">
|
||||||
<Code24 fill="currentColor" />
|
<Code24 fill="currentColor" />
|
||||||
<span class="text-surface-500 -mb-2 flex-1">{$_('page.profile.menu.details.repository')}</span>
|
<span class="text-surface-500 -mb-2 flex-1">{$_('page.profile.menu.details.repository')}</span
|
||||||
|
>
|
||||||
<ChevronDown24 fill="currentColor" />
|
<ChevronDown24 fill="currentColor" />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col ps-4">
|
<div class="flex flex-col ps-4">
|
||||||
|
@ -52,7 +53,8 @@ You should have received a copy of the GNU Affero General Public License along w
|
||||||
</div>
|
</div>
|
||||||
<div class="flex gap-4 bg-white">
|
<div class="flex gap-4 bg-white">
|
||||||
<GitBranch24 fill="currentColor" />
|
<GitBranch24 fill="currentColor" />
|
||||||
<span class="text-surface-500 -mb-2 flex-1">{$_('page.profile.menu.details.branches')}</span>
|
<span class="text-surface-500 -mb-2 flex-1">{$_('page.profile.menu.details.branches')}</span
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex gap-4 bg-white">
|
<div class="flex gap-4 bg-white">
|
||||||
<GitCommit24 fill="currentColor" />
|
<GitCommit24 fill="currentColor" />
|
||||||
|
@ -70,9 +72,10 @@ You should have received a copy of the GNU Affero General Public License along w
|
||||||
</div>
|
</div>
|
||||||
<div class="flex gap-4 bg-white">
|
<div class="flex gap-4 bg-white">
|
||||||
<GitPullRequest24 fill="currentColor" />
|
<GitPullRequest24 fill="currentColor" />
|
||||||
<span class="text-surface-500 -mb-2 flex-1">{$_('page.profile.menu.details.merge_requests')}</span>
|
<span class="text-surface-500 -mb-2 flex-1"
|
||||||
<span
|
>{$_('page.profile.menu.details.merge_requests')}</span
|
||||||
class="text-surface-500 text-center bg-secondary-200 rounded-full min-w-6 self-baseline"
|
>
|
||||||
|
<span class="text-surface-500 text-center bg-secondary-200 rounded-full min-w-6 self-baseline"
|
||||||
>2</span
|
>2</span
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
@ -88,7 +91,9 @@ You should have received a copy of the GNU Affero General Public License along w
|
||||||
</div>
|
</div>
|
||||||
<div class="flex gap-4 bg-white">
|
<div class="flex gap-4 bg-white">
|
||||||
<CommentDiscussion24 fill="currentColor" />
|
<CommentDiscussion24 fill="currentColor" />
|
||||||
<span class="text-surface-500 -mb-2 flex-1">{$_('page.profile.menu.details.moderation')}</span>
|
<span class="text-surface-500 -mb-2 flex-1"
|
||||||
|
>{$_('page.profile.menu.details.moderation')}</span
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex gap-4 bg-white">
|
<div class="flex gap-4 bg-white">
|
||||||
|
@ -98,4 +103,3 @@ You should have received a copy of the GNU Affero General Public License along w
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -14,9 +14,18 @@ You should have received a copy of the GNU Affero General Public License along w
|
||||||
<script>
|
<script>
|
||||||
import SettingsSidebar from '../atoms/SettingsSidebar.svelte';
|
import SettingsSidebar from '../atoms/SettingsSidebar.svelte';
|
||||||
import SettingsProfile from './SettingsProfile.svelte';
|
import SettingsProfile from './SettingsProfile.svelte';
|
||||||
|
|
||||||
|
let activeSetting = 'profile';
|
||||||
|
|
||||||
|
function onTileChanged(ev) {
|
||||||
|
activeSetting = ev.detail;
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="flex bg-surface-50">
|
<div class="flex bg-surface-50">
|
||||||
<SettingsSidebar />
|
<SettingsSidebar on:switch-settings={onTileChanged} />
|
||||||
<SettingsProfile />
|
|
||||||
|
{#if activeSetting === 'profile'}
|
||||||
|
<SettingsProfile />
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -20,6 +20,7 @@ You should have received a copy of the GNU Affero General Public License along w
|
||||||
import Created from '../atoms/Created.svelte';
|
import Created from '../atoms/Created.svelte';
|
||||||
import DisplayName from '../atoms/DisplayName.svelte';
|
import DisplayName from '../atoms/DisplayName.svelte';
|
||||||
import History from '../molecules/History.svelte';
|
import History from '../molecules/History.svelte';
|
||||||
|
import MainMenu from '../molecules/MainMenu.svelte';
|
||||||
import Project from '../molecules/Project.svelte';
|
import Project from '../molecules/Project.svelte';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -71,129 +72,140 @@ You should have received a copy of the GNU Affero General Public License along w
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<section class="w-full mx-auto flex px-8 pt-8">
|
<div class="flex h-full w-full">
|
||||||
<!-- Profile header -->
|
<aside class="w-[400px]">
|
||||||
<div>
|
<MainMenu />
|
||||||
<Avatar avatar={data.user.avatar} displayName={data.user.display_name} />
|
</aside>
|
||||||
</div>
|
<main>
|
||||||
<!-- Board -->
|
<section class="w-full mx-auto flex px-8 pt-8">
|
||||||
<div class="flex flex-1 flex-col ps-8">
|
<!-- Profile header -->
|
||||||
<div class="self-end">
|
<div>
|
||||||
<Created created_at={data.user.created_at} locale={data.locale} />
|
<Avatar avatar={data.user.avatar} displayName={data.user.display_name} />
|
||||||
<BlockOrReport />
|
|
||||||
</div>
|
|
||||||
<!-- Top Row -->
|
|
||||||
<div class="flex mt-2">
|
|
||||||
<!-- Board -->
|
|
||||||
<div class="flex flex-col flex-1 gap-2">
|
|
||||||
<div class="flex items-end">
|
|
||||||
<DisplayName displayName={data.user.display_name} {i18n} pronoun={data.user.pronoun} />
|
|
||||||
</div>
|
|
||||||
<span class="leading-tight">
|
|
||||||
{data.user.username}@{data.user.instance}
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
<!-- Interaction Links -->
|
<!-- Board -->
|
||||||
<button type="button" class="btn-icon border rounded-none self-start">
|
<div class="flex flex-1 flex-col ps-8">
|
||||||
<Star16 fill="currentColor" />
|
<div class="self-end">
|
||||||
</button>
|
<Created created_at={data.user.created_at} locale={data.locale} />
|
||||||
</div>
|
<BlockOrReport />
|
||||||
</div>
|
</div>
|
||||||
</section>
|
<!-- Top Row -->
|
||||||
<section class="w-full h-full mx-auto flex flex-wrap mt-8 px-8">
|
<div class="flex mt-2">
|
||||||
<!-- Board -->
|
<!-- Board -->
|
||||||
<div class="flex flex-1 flex-col px-4">
|
<div class="flex flex-col flex-1 gap-2">
|
||||||
<div class="space-y-6">
|
<div class="flex items-end">
|
||||||
<h2 class="h2 font-semibold leading-tight text-base px-4">
|
<DisplayName
|
||||||
{$_('page.profile.projects.heading')}
|
displayName={data.user.display_name}
|
||||||
</h2>
|
{i18n}
|
||||||
{#if data?.user?.followingsMap}
|
pronoun={data.user.pronoun}
|
||||||
<ul>
|
/>
|
||||||
{#each data.user.followingsMap as following}
|
</div>
|
||||||
{#if following.type === 'Project'}
|
<span class="leading-tight">
|
||||||
<li>
|
{data.user.username}@{data.user.instance}
|
||||||
<Project
|
</span>
|
||||||
collaborators={mapCollaboratorsToMember(
|
</div>
|
||||||
[data.user.person],
|
<!-- Interaction Links -->
|
||||||
data.user.collaboratorsMap,
|
<button type="button" class="btn-icon border rounded-none self-start">
|
||||||
following.id
|
<Star16 fill="currentColor" />
|
||||||
)}
|
</button>
|
||||||
{i18n}
|
</div>
|
||||||
project={following}
|
</div>
|
||||||
/>
|
</section>
|
||||||
</li>
|
<section class="w-full h-full mx-auto flex flex-wrap mt-8 px-8">
|
||||||
{/if}
|
<!-- Board -->
|
||||||
{/each}
|
<div class="flex flex-1 flex-col px-4">
|
||||||
</ul>
|
<div class="space-y-6">
|
||||||
|
<h2 class="h2 font-semibold leading-tight text-base px-4">
|
||||||
|
{$_('page.profile.projects.heading')}
|
||||||
|
</h2>
|
||||||
|
{#if data?.user?.followingsMap}
|
||||||
|
<ul>
|
||||||
|
{#each data.user.followingsMap as following}
|
||||||
|
{#if following.type === 'Project'}
|
||||||
|
<li>
|
||||||
|
<Project
|
||||||
|
collaborators={mapCollaboratorsToMember(
|
||||||
|
[data.user.person],
|
||||||
|
data.user.collaboratorsMap,
|
||||||
|
following.id
|
||||||
|
)}
|
||||||
|
{i18n}
|
||||||
|
project={following}
|
||||||
|
/>
|
||||||
|
</li>
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
|
</ul>
|
||||||
|
|
||||||
<h2 class="h2 font-semibold leading-tight text-base px-4">
|
<h2 class="h2 font-semibold leading-tight text-base px-4">
|
||||||
{$_('page.profile.repositories.heading')}
|
{$_('page.profile.repositories.heading')}
|
||||||
</h2>
|
</h2>
|
||||||
<section class="flex flex-col gap-4">
|
<section class="flex flex-col gap-4">
|
||||||
{#each data.user.followingsMap as following}
|
{#each data.user.followingsMap as following}
|
||||||
{#if following.type === 'Repository'}
|
{#if following.type === 'Repository'}
|
||||||
<div class="border border-surface-100">
|
<div class="border border-surface-100">
|
||||||
<Project collaborators={[]} {i18n} project={following} />
|
<Project collaborators={[]} {i18n} project={following} />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
</section>
|
</section>
|
||||||
<div>
|
<div>
|
||||||
<p>The following is DEBUG information and will be removed in the near future.</p>
|
<p>The following is DEBUG information and will be removed in the near future.</p>
|
||||||
{#if data?.user}
|
{#if data?.user}
|
||||||
<details>
|
<details>
|
||||||
<summary>Person</summary>
|
<summary>Person</summary>
|
||||||
<pre>{JSON.stringify(data.user.person, null, 2)}</pre>
|
<pre>{JSON.stringify(data.user.person, null, 2)}</pre>
|
||||||
</details>
|
</details>
|
||||||
<details>
|
<details>
|
||||||
<summary>Followings</summary>
|
<summary>Followings</summary>
|
||||||
<pre>{JSON.stringify(data.user.followings, null, 2)}</pre>
|
<pre>{JSON.stringify(data.user.followings, null, 2)}</pre>
|
||||||
</details>
|
</details>
|
||||||
<details>
|
<details>
|
||||||
<summary>Followings mapped</summary>
|
<summary>Followings mapped</summary>
|
||||||
<p>These are the contents of the items in the previous dump.</p>
|
<p>These are the contents of the items in the previous dump.</p>
|
||||||
<pre>{JSON.stringify(data.user.followingsMap, null, 2)}</pre>
|
<pre>{JSON.stringify(data.user.followingsMap, null, 2)}</pre>
|
||||||
</details>
|
</details>
|
||||||
<details>
|
<details>
|
||||||
<summary>Collaborators mapped</summary>
|
<summary>Collaborators mapped</summary>
|
||||||
<p>These are the contents of the items in the previous dump.</p>
|
<p>These are the contents of the items in the previous dump.</p>
|
||||||
<pre>{JSON.stringify(data.user.collaboratorsMap, null, 2)}</pre>
|
<pre>{JSON.stringify(data.user.collaboratorsMap, null, 2)}</pre>
|
||||||
</details>
|
</details>
|
||||||
<details>
|
<details>
|
||||||
<summary>Commits</summary>
|
<summary>Commits</summary>
|
||||||
<p>These are the contents of the items in the previous dump.</p>
|
<p>These are the contents of the items in the previous dump.</p>
|
||||||
<pre>{JSON.stringify(data.user.commits, null, 2)}</pre>
|
<pre>{JSON.stringify(data.user.commits, null, 2)}</pre>
|
||||||
</details>
|
</details>
|
||||||
<details>
|
<details>
|
||||||
<summary>Commits mapped</summary>
|
<summary>Commits mapped</summary>
|
||||||
<p>These are the contents of the items in the previous dump.</p>
|
<p>These are the contents of the items in the previous dump.</p>
|
||||||
<pre>{JSON.stringify(data.user.commitsMap, null, 2)}</pre>
|
<pre>{JSON.stringify(data.user.commitsMap, null, 2)}</pre>
|
||||||
</details>
|
</details>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{:else}
|
||||||
|
<p class="px-4">
|
||||||
|
{$_('page.profile.projects.empty')}
|
||||||
|
{@html $_('page.profile.projects.add_or_import', {
|
||||||
|
values: {
|
||||||
|
addElementOpen: '<a class="anchor" href="#">',
|
||||||
|
addElementClose: '</a>',
|
||||||
|
importElementOpen: `<a class="anchor" href="/projects/import/" data-sb-kind=${sb}>`,
|
||||||
|
importElementClose: '</a>'
|
||||||
|
}
|
||||||
|
})}
|
||||||
|
</p>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
</div>
|
||||||
<p class="px-4">
|
<!-- History -->
|
||||||
{$_('page.profile.projects.empty')}
|
<div class="flex flex-1 flex-col px-4">
|
||||||
{@html $_('page.profile.projects.add_or_import', {
|
<div class="space-y-6">
|
||||||
values: {
|
<History
|
||||||
addElementOpen: '<a class="anchor" href="#">',
|
commitsMap={data?.user?.commitsMap || []}
|
||||||
addElementClose: '</a>',
|
{data}
|
||||||
importElementOpen: `<a class="anchor" href="/projects/import/" data-sb-kind=${sb}>`,
|
followingsMap={data?.user?.followingsMap || []}
|
||||||
importElementClose: '</a>'
|
/>
|
||||||
}
|
</div>
|
||||||
})}
|
</div>
|
||||||
</p>
|
</section>
|
||||||
{/if}
|
</main>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<!-- History -->
|
|
||||||
<div class="flex flex-1 flex-col px-4">
|
|
||||||
<div class="space-y-6">
|
|
||||||
<History
|
|
||||||
commitsMap={data?.user?.commitsMap || []}
|
|
||||||
{data}
|
|
||||||
followingsMap={data?.user?.followingsMap || []}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
|
@ -7,8 +7,10 @@ SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { locale } from 'svelte-i18n';
|
import { locale } from 'svelte-i18n';
|
||||||
import { initializeStores } from '@skeletonlabs/skeleton';
|
import { computePosition, autoUpdate, offset, shift, flip, arrow } from '@floating-ui/dom';
|
||||||
|
import { initializeStores, storePopup, Modal } from '@skeletonlabs/skeleton';
|
||||||
|
|
||||||
|
import Settings from '$lib/components/molecules/Settings.svelte';
|
||||||
import { mapLocaleToDir } from '$lib/i18n';
|
import { mapLocaleToDir } from '$lib/i18n';
|
||||||
|
|
||||||
// The ordering of these imports is critical to your app working properly
|
// The ordering of these imports is critical to your app working properly
|
||||||
|
@ -25,8 +27,14 @@ SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const modalRegistry = {
|
||||||
|
settings: { ref: Settings }
|
||||||
|
};
|
||||||
|
|
||||||
initializeStores();
|
initializeStores();
|
||||||
|
storePopup.set({ computePosition, autoUpdate, offset, shift, flip, arrow });
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<Modal components={modalRegistry} />
|
||||||
<!-- Page Route Content -->
|
<!-- Page Route Content -->
|
||||||
<slot />
|
<slot />
|
||||||
|
|
26
stories/molecules/Settings.stories.ts
Normal file
26
stories/molecules/Settings.stories.ts
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
/* Stories for Settings molecule.
|
||||||
|
* Copyright (C) 2024 André Jaenisch
|
||||||
|
* SPDX-FileCopyrightText: 2024 André Jaenisch
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type { Meta, StoryObj } from '@storybook/svelte';
|
||||||
|
|
||||||
|
import Settings from '$lib/components/molecules/Settings.svelte';
|
||||||
|
|
||||||
|
const meta = {
|
||||||
|
title: 'Molecules/Settings',
|
||||||
|
component: Settings,
|
||||||
|
tags: ['autodocs']
|
||||||
|
} satisfies Meta<Settings>;
|
||||||
|
|
||||||
|
export default meta;
|
||||||
|
type Story = StoryObj<typeof meta>;
|
||||||
|
|
||||||
|
export const Plain: Story = {};
|
|
@ -14,7 +14,7 @@ import { computePosition, autoUpdate, offset, shift, flip, arrow } from '@floati
|
||||||
import { storePopup } from '@skeletonlabs/skeleton';
|
import { storePopup } from '@skeletonlabs/skeleton';
|
||||||
import '@testing-library/jest-dom';
|
import '@testing-library/jest-dom';
|
||||||
import { render, screen } from '@testing-library/svelte';
|
import { render, screen } from '@testing-library/svelte';
|
||||||
import { get, readable } from 'svelte/store';
|
import { readable } from 'svelte/store';
|
||||||
import { init, locale, register } from 'svelte-i18n';
|
import { init, locale, register } from 'svelte-i18n';
|
||||||
|
|
||||||
import MainMenuSummary from '../../../src/lib/components/atoms/MainMenuSummary.svelte';
|
import MainMenuSummary from '../../../src/lib/components/atoms/MainMenuSummary.svelte';
|
||||||
|
|
|
@ -27,13 +27,10 @@ describe('SettingsSidebar.svelte', () => {
|
||||||
|
|
||||||
it('should mount', () => {
|
it('should mount', () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
// See https://testing-library.com/docs/svelte-testing-library/example#contexts
|
// Nothing to prepare
|
||||||
const drawerStore = readable([]);
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
const { container } = render(SettingsSidebar, {
|
const { container } = render(SettingsSidebar);
|
||||||
context: new Map([['drawerStore', drawerStore]])
|
|
||||||
});
|
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(container).toBeTruthy();
|
expect(container).toBeTruthy();
|
||||||
|
@ -41,13 +38,10 @@ describe('SettingsSidebar.svelte', () => {
|
||||||
|
|
||||||
it('should have a headline', () => {
|
it('should have a headline', () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
// See https://testing-library.com/docs/svelte-testing-library/example#contexts
|
// Nothing to prepare
|
||||||
const drawerStore = readable([]);
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
render(SettingsSidebar, {
|
render(SettingsSidebar);
|
||||||
context: new Map([['drawerStore', drawerStore]])
|
|
||||||
});
|
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(screen.getByText(enMessages.settings.headline)).toBeInTheDocument();
|
expect(screen.getByText(enMessages.settings.headline)).toBeInTheDocument();
|
||||||
|
@ -55,13 +49,10 @@ describe('SettingsSidebar.svelte', () => {
|
||||||
|
|
||||||
it('should have a profile tile', () => {
|
it('should have a profile tile', () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
// See https://testing-library.com/docs/svelte-testing-library/example#contexts
|
// Nothing to prepare
|
||||||
const drawerStore = readable([]);
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
render(SettingsSidebar, {
|
render(SettingsSidebar);
|
||||||
context: new Map([['drawerStore', drawerStore]])
|
|
||||||
});
|
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(screen.getByText(enMessages.settings.profile.label)).toBeInTheDocument();
|
expect(screen.getByText(enMessages.settings.profile.label)).toBeInTheDocument();
|
||||||
|
@ -69,13 +60,10 @@ describe('SettingsSidebar.svelte', () => {
|
||||||
|
|
||||||
it('should have an account tile', () => {
|
it('should have an account tile', () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
// See https://testing-library.com/docs/svelte-testing-library/example#contexts
|
// Nothing to prepare
|
||||||
const drawerStore = readable([]);
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
render(SettingsSidebar, {
|
render(SettingsSidebar);
|
||||||
context: new Map([['drawerStore', drawerStore]])
|
|
||||||
});
|
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(screen.getByText(enMessages.settings.account.label)).toBeInTheDocument();
|
expect(screen.getByText(enMessages.settings.account.label)).toBeInTheDocument();
|
||||||
|
@ -83,13 +71,10 @@ describe('SettingsSidebar.svelte', () => {
|
||||||
|
|
||||||
it('should have a SSH/GPG keys tile', () => {
|
it('should have a SSH/GPG keys tile', () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
// See https://testing-library.com/docs/svelte-testing-library/example#contexts
|
// Nothing to prepare
|
||||||
const drawerStore = readable([]);
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
render(SettingsSidebar, {
|
render(SettingsSidebar);
|
||||||
context: new Map([['drawerStore', drawerStore]])
|
|
||||||
});
|
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(screen.getByText(enMessages.settings.ssh_gpg_keys.label)).toBeInTheDocument();
|
expect(screen.getByText(enMessages.settings.ssh_gpg_keys.label)).toBeInTheDocument();
|
||||||
|
@ -97,13 +82,10 @@ describe('SettingsSidebar.svelte', () => {
|
||||||
|
|
||||||
it('should have an appearance tile', () => {
|
it('should have an appearance tile', () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
// See https://testing-library.com/docs/svelte-testing-library/example#contexts
|
// Nothing to prepare
|
||||||
const drawerStore = readable([]);
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
render(SettingsSidebar, {
|
render(SettingsSidebar);
|
||||||
context: new Map([['drawerStore', drawerStore]])
|
|
||||||
});
|
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(screen.getByText(enMessages.settings.appearance.label)).toBeInTheDocument();
|
expect(screen.getByText(enMessages.settings.appearance.label)).toBeInTheDocument();
|
||||||
|
@ -111,15 +93,48 @@ describe('SettingsSidebar.svelte', () => {
|
||||||
|
|
||||||
it('should have a notifications tile', () => {
|
it('should have a notifications tile', () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
// See https://testing-library.com/docs/svelte-testing-library/example#contexts
|
// Nothing to prepare
|
||||||
const drawerStore = readable([]);
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
render(SettingsSidebar, {
|
render(SettingsSidebar);
|
||||||
context: new Map([['drawerStore', drawerStore]])
|
|
||||||
});
|
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(screen.getByText(enMessages.settings.notifications.label)).toBeInTheDocument();
|
expect(screen.getByText(enMessages.settings.notifications.label)).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('when clicking a tile', () => {
|
||||||
|
it('should dispatch a switch-settings event when clicking a tile', () => {
|
||||||
|
// Arrange
|
||||||
|
const listener = vi.fn();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const { component } = render(SettingsSidebar);
|
||||||
|
component.$on('switch-settings', listener);
|
||||||
|
const profileTile = screen.getByText(enMessages.settings.profile.label);
|
||||||
|
expect(profileTile).toBeInTheDocument();
|
||||||
|
profileTile.click();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(listener).toHaveBeenCalledOnce();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should pass the clicked tile in the event', () => {
|
||||||
|
// Arrange
|
||||||
|
const listener = vi.fn();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const { component } = render(SettingsSidebar);
|
||||||
|
component.$on('switch-settings', listener);
|
||||||
|
const profileTile = screen.getByText(enMessages.settings.profile.label);
|
||||||
|
expect(profileTile).toBeInTheDocument();
|
||||||
|
profileTile.click();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(listener).toHaveBeenCalledWith(
|
||||||
|
new CustomEvent('switch-settings', {
|
||||||
|
detail: 'profile'
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -109,7 +109,9 @@ describe('MainMenuDetails.svelte', () => {
|
||||||
render(MainMenuDetails);
|
render(MainMenuDetails);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(screen.getByText(enMessages.page.profile.menu.details.merge_requests)).toBeInTheDocument();
|
expect(
|
||||||
|
screen.getByText(enMessages.page.profile.menu.details.merge_requests)
|
||||||
|
).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should have a people item', () => {
|
it('should have a people item', () => {
|
||||||
|
|
72
tests/components/molecules/Settings.test.ts
Normal file
72
tests/components/molecules/Settings.test.ts
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
/* Component test for Settings molecule.
|
||||||
|
* Copyright (C) 2024 André Jaenisch
|
||||||
|
* SPDX-FileCopyrightText: 2024 André Jaenisch
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import '@testing-library/jest-dom';
|
||||||
|
import { render, screen } from '@testing-library/svelte';
|
||||||
|
import { tick } from 'svelte';
|
||||||
|
import { init, locale, register } from 'svelte-i18n';
|
||||||
|
|
||||||
|
import Settings from '../../../src/lib/components/molecules/Settings.svelte';
|
||||||
|
import enMessages from '../../../src/lib/i18n/locales/en.json';
|
||||||
|
|
||||||
|
describe('Settings.svelte', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
register('en', () => import('../../../src/lib/i18n/locales/en.json'));
|
||||||
|
init({ fallbackLocale: 'en', initialLocale: 'en' });
|
||||||
|
locale.set('en');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should mount', () => {
|
||||||
|
// Arrange
|
||||||
|
// Nothing to prepare
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const { container } = render(Settings);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(container).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have an profile section', () => {
|
||||||
|
// Arrange
|
||||||
|
// Nothing to prepare
|
||||||
|
|
||||||
|
// Act
|
||||||
|
render(Settings);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
// There are multiple nodes with that name and I haven't determined the appropriate heading level
|
||||||
|
expect(screen.getAllByText(enMessages.settings.profile.headline)).not.toHaveLength(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when switching the active setting', () => {
|
||||||
|
it('should not have an profile section', async () => {
|
||||||
|
// Arrange
|
||||||
|
// Nothing to prepare
|
||||||
|
|
||||||
|
// Act
|
||||||
|
render(Settings);
|
||||||
|
const profileTileAndSection = screen.getAllByText(
|
||||||
|
enMessages.settings.profile.headline
|
||||||
|
).length;
|
||||||
|
const notificationTile = screen.getByText(enMessages.settings.notifications.label);
|
||||||
|
notificationTile.click();
|
||||||
|
// Wait for reactivity
|
||||||
|
await tick();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(screen.queryAllByText(enMessages.settings.profile.headline).length).toBeLessThan(
|
||||||
|
profileTileAndSection
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -10,9 +10,12 @@
|
||||||
* You should have received a copy of the GNU Affero General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* You should have received a copy of the GNU Affero General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { computePosition, autoUpdate, offset, shift, flip, arrow } from '@floating-ui/dom';
|
||||||
|
import { storePopup } from '@skeletonlabs/skeleton';
|
||||||
import '@testing-library/jest-dom';
|
import '@testing-library/jest-dom';
|
||||||
import { render, screen } from '@testing-library/svelte';
|
import { render, screen } from '@testing-library/svelte';
|
||||||
import { init, locale, register } from 'svelte-i18n';
|
import { init, locale, register } from 'svelte-i18n';
|
||||||
|
import { readable } from 'svelte/store';
|
||||||
|
|
||||||
import Profile from '../../../src/lib/components/pages/Profile.svelte';
|
import Profile from '../../../src/lib/components/pages/Profile.svelte';
|
||||||
import enMessages from '../../../src/lib/i18n/locales/en.json';
|
import enMessages from '../../../src/lib/i18n/locales/en.json';
|
||||||
|
@ -26,12 +29,24 @@ describe('Profile.svelte', () => {
|
||||||
|
|
||||||
it('should mount', () => {
|
it('should mount', () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const data = {
|
// See https://testing-library.com/docs/svelte-testing-library/example#contexts
|
||||||
user: {}
|
const modalStore = readable([]);
|
||||||
|
// See https://www.skeleton.dev/utilities/popups
|
||||||
|
storePopup.set({ computePosition, autoUpdate, offset, shift, flip, arrow });
|
||||||
|
|
||||||
|
const props = {
|
||||||
|
data: {
|
||||||
|
user: {}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const context = new Map([
|
||||||
|
['modalStore', modalStore],
|
||||||
|
['storePopup', storePopup]
|
||||||
|
]);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
const { container } = render(Profile, { data });
|
const { container } = render(Profile, { context, props });
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(container).toBeTruthy();
|
expect(container).toBeTruthy();
|
||||||
|
@ -39,12 +54,24 @@ describe('Profile.svelte', () => {
|
||||||
|
|
||||||
it('should have a h1', () => {
|
it('should have a h1', () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const data = {
|
// See https://testing-library.com/docs/svelte-testing-library/example#contexts
|
||||||
user: {}
|
const modalStore = readable([]);
|
||||||
|
// See https://www.skeleton.dev/utilities/popups
|
||||||
|
storePopup.set({ computePosition, autoUpdate, offset, shift, flip, arrow });
|
||||||
|
|
||||||
|
const props = {
|
||||||
|
data: {
|
||||||
|
user: {}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const context = new Map([
|
||||||
|
['modalStore', modalStore],
|
||||||
|
['storePopup', storePopup]
|
||||||
|
]);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
render(Profile, { data });
|
render(Profile, { context, props });
|
||||||
const h1 = screen.getByRole('heading', { level: 1 });
|
const h1 = screen.getByRole('heading', { level: 1 });
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
|
@ -54,12 +81,24 @@ describe('Profile.svelte', () => {
|
||||||
|
|
||||||
it('should have a block button', () => {
|
it('should have a block button', () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const data = {
|
// See https://testing-library.com/docs/svelte-testing-library/example#contexts
|
||||||
user: {}
|
const modalStore = readable([]);
|
||||||
|
// See https://www.skeleton.dev/utilities/popups
|
||||||
|
storePopup.set({ computePosition, autoUpdate, offset, shift, flip, arrow });
|
||||||
|
|
||||||
|
const props = {
|
||||||
|
data: {
|
||||||
|
user: {}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const context = new Map([
|
||||||
|
['modalStore', modalStore],
|
||||||
|
['storePopup', storePopup]
|
||||||
|
]);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
render(Profile, { data });
|
render(Profile, { context, props });
|
||||||
const button = screen.getByRole('button', { name: 'block' });
|
const button = screen.getByRole('button', { name: 'block' });
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
|
@ -68,12 +107,24 @@ describe('Profile.svelte', () => {
|
||||||
|
|
||||||
it('should have a report button', () => {
|
it('should have a report button', () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const data = {
|
// See https://testing-library.com/docs/svelte-testing-library/example#contexts
|
||||||
user: {}
|
const modalStore = readable([]);
|
||||||
|
// See https://www.skeleton.dev/utilities/popups
|
||||||
|
storePopup.set({ computePosition, autoUpdate, offset, shift, flip, arrow });
|
||||||
|
|
||||||
|
const props = {
|
||||||
|
data: {
|
||||||
|
user: {}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const context = new Map([
|
||||||
|
['modalStore', modalStore],
|
||||||
|
['storePopup', storePopup]
|
||||||
|
]);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
render(Profile, { data });
|
render(Profile, { context, props });
|
||||||
const button = screen.getByRole('button', { name: 'report' });
|
const button = screen.getByRole('button', { name: 'report' });
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
|
@ -83,12 +134,24 @@ describe('Profile.svelte', () => {
|
||||||
// FIXME: Reenable once emoji was replaced with svelte-octicon
|
// FIXME: Reenable once emoji was replaced with svelte-octicon
|
||||||
it.skip('should have a like button', () => {
|
it.skip('should have a like button', () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const data = {
|
// See https://testing-library.com/docs/svelte-testing-library/example#contexts
|
||||||
user: {}
|
const modalStore = readable([]);
|
||||||
|
// See https://www.skeleton.dev/utilities/popups
|
||||||
|
storePopup.set({ computePosition, autoUpdate, offset, shift, flip, arrow });
|
||||||
|
|
||||||
|
const props = {
|
||||||
|
data: {
|
||||||
|
user: {}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const context = new Map([
|
||||||
|
['modalStore', modalStore],
|
||||||
|
['storePopup', storePopup]
|
||||||
|
]);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
render(Profile, { data });
|
render(Profile, { context, props });
|
||||||
const button = screen.getByRole('button', { name: enMessages.page.profile.activities.like });
|
const button = screen.getByRole('button', { name: enMessages.page.profile.activities.like });
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
|
@ -98,12 +161,24 @@ describe('Profile.svelte', () => {
|
||||||
describe('projects', () => {
|
describe('projects', () => {
|
||||||
it('should have a h2', () => {
|
it('should have a h2', () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const data = {
|
// See https://testing-library.com/docs/svelte-testing-library/example#contexts
|
||||||
user: {}
|
const modalStore = readable([]);
|
||||||
|
// See https://www.skeleton.dev/utilities/popups
|
||||||
|
storePopup.set({ computePosition, autoUpdate, offset, shift, flip, arrow });
|
||||||
|
|
||||||
|
const props = {
|
||||||
|
data: {
|
||||||
|
user: {}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const context = new Map([
|
||||||
|
['modalStore', modalStore],
|
||||||
|
['storePopup', storePopup]
|
||||||
|
]);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
render(Profile, { data });
|
render(Profile, { context, props });
|
||||||
const h2 = screen.getByRole('heading', {
|
const h2 = screen.getByRole('heading', {
|
||||||
level: 2,
|
level: 2,
|
||||||
name: enMessages.page.profile.projects.heading
|
name: enMessages.page.profile.projects.heading
|
||||||
|
@ -115,12 +190,24 @@ describe('Profile.svelte', () => {
|
||||||
|
|
||||||
it('should add a project', () => {
|
it('should add a project', () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const data = {
|
// See https://testing-library.com/docs/svelte-testing-library/example#contexts
|
||||||
user: {}
|
const modalStore = readable([]);
|
||||||
|
// See https://www.skeleton.dev/utilities/popups
|
||||||
|
storePopup.set({ computePosition, autoUpdate, offset, shift, flip, arrow });
|
||||||
|
|
||||||
|
const props = {
|
||||||
|
data: {
|
||||||
|
user: {}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const context = new Map([
|
||||||
|
['modalStore', modalStore],
|
||||||
|
['storePopup', storePopup]
|
||||||
|
]);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
render(Profile, { data });
|
render(Profile, { context, props });
|
||||||
const a = screen.getByRole('link', { name: 'Add a project' });
|
const a = screen.getByRole('link', { name: 'Add a project' });
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
|
@ -129,12 +216,24 @@ describe('Profile.svelte', () => {
|
||||||
|
|
||||||
it('should import a project', () => {
|
it('should import a project', () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const data = {
|
// See https://testing-library.com/docs/svelte-testing-library/example#contexts
|
||||||
user: {}
|
const modalStore = readable([]);
|
||||||
|
// See https://www.skeleton.dev/utilities/popups
|
||||||
|
storePopup.set({ computePosition, autoUpdate, offset, shift, flip, arrow });
|
||||||
|
|
||||||
|
const props = {
|
||||||
|
data: {
|
||||||
|
user: {}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const context = new Map([
|
||||||
|
['modalStore', modalStore],
|
||||||
|
['storePopup', storePopup]
|
||||||
|
]);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
render(Profile, { data });
|
render(Profile, { context, props });
|
||||||
const a = screen.getByRole('link', { name: 'import a project' });
|
const a = screen.getByRole('link', { name: 'import a project' });
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
|
@ -146,12 +245,24 @@ describe('Profile.svelte', () => {
|
||||||
describe('history', () => {
|
describe('history', () => {
|
||||||
it('should have a h2', () => {
|
it('should have a h2', () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const data = {
|
// See https://testing-library.com/docs/svelte-testing-library/example#contexts
|
||||||
user: {}
|
const modalStore = readable([]);
|
||||||
|
// See https://www.skeleton.dev/utilities/popups
|
||||||
|
storePopup.set({ computePosition, autoUpdate, offset, shift, flip, arrow });
|
||||||
|
|
||||||
|
const props = {
|
||||||
|
data: {
|
||||||
|
user: {}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const context = new Map([
|
||||||
|
['modalStore', modalStore],
|
||||||
|
['storePopup', storePopup]
|
||||||
|
]);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
render(Profile, { data });
|
render(Profile, { context, props });
|
||||||
const h2 = screen.getByRole('heading', {
|
const h2 = screen.getByRole('heading', {
|
||||||
level: 2,
|
level: 2,
|
||||||
name: enMessages.page.profile.history.heading
|
name: enMessages.page.profile.history.heading
|
||||||
|
@ -163,16 +274,28 @@ describe('Profile.svelte', () => {
|
||||||
|
|
||||||
it('should have an entry for created account', () => {
|
it('should have an entry for created account', () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const data = {
|
// See https://testing-library.com/docs/svelte-testing-library/example#contexts
|
||||||
user: {
|
const modalStore = readable([]);
|
||||||
created_with: 'Anvil',
|
// See https://www.skeleton.dev/utilities/popups
|
||||||
instance: 'domain.example',
|
storePopup.set({ computePosition, autoUpdate, offset, shift, flip, arrow });
|
||||||
username: 'jane_doe'
|
|
||||||
|
const props = {
|
||||||
|
data: {
|
||||||
|
user: {
|
||||||
|
created_with: 'Anvil',
|
||||||
|
instance: 'domain.example',
|
||||||
|
username: 'jane_doe'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const context = new Map([
|
||||||
|
['modalStore', modalStore],
|
||||||
|
['storePopup', storePopup]
|
||||||
|
]);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
render(Profile, { data });
|
render(Profile, { context, props });
|
||||||
const li = screen.getByRole('listitem');
|
const li = screen.getByRole('listitem');
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
|
@ -183,9 +306,9 @@ describe('Profile.svelte', () => {
|
||||||
expect(li).toHaveTextContent(
|
expect(li).toHaveTextContent(
|
||||||
new RegExp(
|
new RegExp(
|
||||||
enMessages.page.profile.history.activities.setup.description
|
enMessages.page.profile.history.activities.setup.description
|
||||||
.replace('{username}', data.user.username)
|
.replace('{username}', props.data.user.username)
|
||||||
.replace('{instance}', data.user.instance)
|
.replace('{instance}', props.data.user.instance)
|
||||||
.replace('{created_with}', data.user.created_with)
|
.replace('{created_with}', props.data.user.created_with)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
|
@ -10,9 +10,12 @@
|
||||||
* You should have received a copy of the GNU Affero General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* You should have received a copy of the GNU Affero General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { computePosition, autoUpdate, offset, shift, flip, arrow } from '@floating-ui/dom';
|
||||||
|
import { storePopup } from '@skeletonlabs/skeleton';
|
||||||
import '@testing-library/jest-dom';
|
import '@testing-library/jest-dom';
|
||||||
import { render, screen } from '@testing-library/svelte';
|
import { render, screen } from '@testing-library/svelte';
|
||||||
import { init, locale, register } from 'svelte-i18n';
|
import { init, locale, register } from 'svelte-i18n';
|
||||||
|
import { readable } from 'svelte/store';
|
||||||
|
|
||||||
import Profile from '../../../src/lib/components/templates/Profile.svelte';
|
import Profile from '../../../src/lib/components/templates/Profile.svelte';
|
||||||
import enMessages from '../../../src/lib/i18n/locales/en.json';
|
import enMessages from '../../../src/lib/i18n/locales/en.json';
|
||||||
|
@ -26,12 +29,24 @@ describe('Profile.svelte', () => {
|
||||||
|
|
||||||
it('should mount', () => {
|
it('should mount', () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const data = {
|
// See https://testing-library.com/docs/svelte-testing-library/example#contexts
|
||||||
user: {}
|
const modalStore = readable([]);
|
||||||
|
// See https://www.skeleton.dev/utilities/popups
|
||||||
|
storePopup.set({ computePosition, autoUpdate, offset, shift, flip, arrow });
|
||||||
|
|
||||||
|
const props = {
|
||||||
|
data: {
|
||||||
|
user: {}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const context = new Map([
|
||||||
|
['modalStore', modalStore],
|
||||||
|
['storePopup', storePopup]
|
||||||
|
]);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
const { container } = render(Profile, { data });
|
const { container } = render(Profile, { context, props });
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(container).toBeTruthy();
|
expect(container).toBeTruthy();
|
||||||
|
@ -39,12 +54,24 @@ describe('Profile.svelte', () => {
|
||||||
|
|
||||||
it('should have a h1', () => {
|
it('should have a h1', () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const data = {
|
// See https://testing-library.com/docs/svelte-testing-library/example#contexts
|
||||||
user: {}
|
const modalStore = readable([]);
|
||||||
|
// See https://www.skeleton.dev/utilities/popups
|
||||||
|
storePopup.set({ computePosition, autoUpdate, offset, shift, flip, arrow });
|
||||||
|
|
||||||
|
const props = {
|
||||||
|
data: {
|
||||||
|
user: {}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const context = new Map([
|
||||||
|
['modalStore', modalStore],
|
||||||
|
['storePopup', storePopup]
|
||||||
|
]);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
render(Profile, { data });
|
render(Profile, { context, props });
|
||||||
const h1 = screen.getByRole('heading', { level: 1 });
|
const h1 = screen.getByRole('heading', { level: 1 });
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
|
@ -54,12 +81,24 @@ describe('Profile.svelte', () => {
|
||||||
|
|
||||||
it('should have a block button', () => {
|
it('should have a block button', () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const data = {
|
// See https://testing-library.com/docs/svelte-testing-library/example#contexts
|
||||||
user: {}
|
const modalStore = readable([]);
|
||||||
|
// See https://www.skeleton.dev/utilities/popups
|
||||||
|
storePopup.set({ computePosition, autoUpdate, offset, shift, flip, arrow });
|
||||||
|
|
||||||
|
const props = {
|
||||||
|
data: {
|
||||||
|
user: {}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const context = new Map([
|
||||||
|
['modalStore', modalStore],
|
||||||
|
['storePopup', storePopup]
|
||||||
|
]);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
render(Profile, { data });
|
render(Profile, { context, props });
|
||||||
const button = screen.getByRole('button', { name: 'block' });
|
const button = screen.getByRole('button', { name: 'block' });
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
|
@ -68,12 +107,24 @@ describe('Profile.svelte', () => {
|
||||||
|
|
||||||
it('should have a report button', () => {
|
it('should have a report button', () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const data = {
|
// See https://testing-library.com/docs/svelte-testing-library/example#contexts
|
||||||
user: {}
|
const modalStore = readable([]);
|
||||||
|
// See https://www.skeleton.dev/utilities/popups
|
||||||
|
storePopup.set({ computePosition, autoUpdate, offset, shift, flip, arrow });
|
||||||
|
|
||||||
|
const props = {
|
||||||
|
data: {
|
||||||
|
user: {}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const context = new Map([
|
||||||
|
['modalStore', modalStore],
|
||||||
|
['storePopup', storePopup]
|
||||||
|
]);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
render(Profile, { data });
|
render(Profile, { context, props });
|
||||||
const button = screen.getByRole('button', { name: 'report' });
|
const button = screen.getByRole('button', { name: 'report' });
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
|
@ -83,12 +134,24 @@ describe('Profile.svelte', () => {
|
||||||
// FIXME: Reenable once emoji was replaced with svelte-octicon
|
// FIXME: Reenable once emoji was replaced with svelte-octicon
|
||||||
it.skip('should have a like button', () => {
|
it.skip('should have a like button', () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const data = {
|
// See https://testing-library.com/docs/svelte-testing-library/example#contexts
|
||||||
user: {}
|
const modalStore = readable([]);
|
||||||
|
// See https://www.skeleton.dev/utilities/popups
|
||||||
|
storePopup.set({ computePosition, autoUpdate, offset, shift, flip, arrow });
|
||||||
|
|
||||||
|
const props = {
|
||||||
|
data: {
|
||||||
|
user: {}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const context = new Map([
|
||||||
|
['modalStore', modalStore],
|
||||||
|
['storePopup', storePopup]
|
||||||
|
]);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
render(Profile, { data });
|
render(Profile, { context, props });
|
||||||
const button = screen.getByRole('button', { name: enMessages.page.profile.activities.like });
|
const button = screen.getByRole('button', { name: enMessages.page.profile.activities.like });
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
|
@ -98,12 +161,24 @@ describe('Profile.svelte', () => {
|
||||||
describe('projects', () => {
|
describe('projects', () => {
|
||||||
it('should have a h2', () => {
|
it('should have a h2', () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const data = {
|
// See https://testing-library.com/docs/svelte-testing-library/example#contexts
|
||||||
user: {}
|
const modalStore = readable([]);
|
||||||
|
// See https://www.skeleton.dev/utilities/popups
|
||||||
|
storePopup.set({ computePosition, autoUpdate, offset, shift, flip, arrow });
|
||||||
|
|
||||||
|
const props = {
|
||||||
|
data: {
|
||||||
|
user: {}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const context = new Map([
|
||||||
|
['modalStore', modalStore],
|
||||||
|
['storePopup', storePopup]
|
||||||
|
]);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
render(Profile, { data });
|
render(Profile, { context, props });
|
||||||
const h2 = screen.getByRole('heading', {
|
const h2 = screen.getByRole('heading', {
|
||||||
level: 2,
|
level: 2,
|
||||||
name: enMessages.page.profile.projects.heading
|
name: enMessages.page.profile.projects.heading
|
||||||
|
@ -115,12 +190,24 @@ describe('Profile.svelte', () => {
|
||||||
|
|
||||||
it('should add a project', () => {
|
it('should add a project', () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const data = {
|
// See https://testing-library.com/docs/svelte-testing-library/example#contexts
|
||||||
user: {}
|
const modalStore = readable([]);
|
||||||
|
// See https://www.skeleton.dev/utilities/popups
|
||||||
|
storePopup.set({ computePosition, autoUpdate, offset, shift, flip, arrow });
|
||||||
|
|
||||||
|
const props = {
|
||||||
|
data: {
|
||||||
|
user: {}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const context = new Map([
|
||||||
|
['modalStore', modalStore],
|
||||||
|
['storePopup', storePopup]
|
||||||
|
]);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
render(Profile, { data });
|
render(Profile, { context, props });
|
||||||
const a = screen.getByRole('link', { name: 'Add a project' });
|
const a = screen.getByRole('link', { name: 'Add a project' });
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
|
@ -129,12 +216,24 @@ describe('Profile.svelte', () => {
|
||||||
|
|
||||||
it('should import a project', () => {
|
it('should import a project', () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const data = {
|
// See https://testing-library.com/docs/svelte-testing-library/example#contexts
|
||||||
user: {}
|
const modalStore = readable([]);
|
||||||
|
// See https://www.skeleton.dev/utilities/popups
|
||||||
|
storePopup.set({ computePosition, autoUpdate, offset, shift, flip, arrow });
|
||||||
|
|
||||||
|
const props = {
|
||||||
|
data: {
|
||||||
|
user: {}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const context = new Map([
|
||||||
|
['modalStore', modalStore],
|
||||||
|
['storePopup', storePopup]
|
||||||
|
]);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
render(Profile, { data });
|
render(Profile, { context, props });
|
||||||
const a = screen.getByRole('link', { name: 'import a project' });
|
const a = screen.getByRole('link', { name: 'import a project' });
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
|
@ -146,12 +245,24 @@ describe('Profile.svelte', () => {
|
||||||
describe('history', () => {
|
describe('history', () => {
|
||||||
it('should have a h2', () => {
|
it('should have a h2', () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const data = {
|
// See https://testing-library.com/docs/svelte-testing-library/example#contexts
|
||||||
user: {}
|
const modalStore = readable([]);
|
||||||
|
// See https://www.skeleton.dev/utilities/popups
|
||||||
|
storePopup.set({ computePosition, autoUpdate, offset, shift, flip, arrow });
|
||||||
|
|
||||||
|
const props = {
|
||||||
|
data: {
|
||||||
|
user: {}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const context = new Map([
|
||||||
|
['modalStore', modalStore],
|
||||||
|
['storePopup', storePopup]
|
||||||
|
]);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
render(Profile, { data });
|
render(Profile, { context, props });
|
||||||
const h2 = screen.getByRole('heading', {
|
const h2 = screen.getByRole('heading', {
|
||||||
level: 2,
|
level: 2,
|
||||||
name: enMessages.page.profile.history.heading
|
name: enMessages.page.profile.history.heading
|
||||||
|
@ -163,16 +274,28 @@ describe('Profile.svelte', () => {
|
||||||
|
|
||||||
it('should have an entry for created account', () => {
|
it('should have an entry for created account', () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const data = {
|
// See https://testing-library.com/docs/svelte-testing-library/example#contexts
|
||||||
user: {
|
const modalStore = readable([]);
|
||||||
created_with: 'Anvil',
|
// See https://www.skeleton.dev/utilities/popups
|
||||||
instance: 'domain.example',
|
storePopup.set({ computePosition, autoUpdate, offset, shift, flip, arrow });
|
||||||
username: 'jane_doe'
|
|
||||||
|
const props = {
|
||||||
|
data: {
|
||||||
|
user: {
|
||||||
|
created_with: 'Anvil',
|
||||||
|
instance: 'domain.example',
|
||||||
|
username: 'jane_doe'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const context = new Map([
|
||||||
|
['modalStore', modalStore],
|
||||||
|
['storePopup', storePopup]
|
||||||
|
]);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
render(Profile, { data });
|
render(Profile, { context, props });
|
||||||
const li = screen.getByRole('listitem');
|
const li = screen.getByRole('listitem');
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
|
@ -183,9 +306,9 @@ describe('Profile.svelte', () => {
|
||||||
expect(li).toHaveTextContent(
|
expect(li).toHaveTextContent(
|
||||||
new RegExp(
|
new RegExp(
|
||||||
enMessages.page.profile.history.activities.setup.description
|
enMessages.page.profile.history.activities.setup.description
|
||||||
.replace('{username}', data.user.username)
|
.replace('{username}', props.data.user.username)
|
||||||
.replace('{instance}', data.user.instance)
|
.replace('{instance}', props.data.user.instance)
|
||||||
.replace('{created_with}', data.user.created_with)
|
.replace('{created_with}', props.data.user.created_with)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue