diff options
Diffstat (limited to 'src/lib/components/topic')
| -rw-r--r-- | src/lib/components/topic/topic.svelte | 44 | ||||
| -rw-r--r-- | src/lib/components/topic/topic.test.ts | 168 |
2 files changed, 212 insertions, 0 deletions
diff --git a/src/lib/components/topic/topic.svelte b/src/lib/components/topic/topic.svelte new file mode 100644 index 0000000..06f2aeb --- /dev/null +++ b/src/lib/components/topic/topic.svelte @@ -0,0 +1,44 @@ +<script lang="ts"> + export let topic; + + import { _ } from 'svelte-i18n'; + import Post from '$lib/components/post/post.svelte'; + import { readableTime } from '$lib/utils/readable_time'; + + $: remainingTime = topic.updated_at + topic.ttl - Date.now(); + $: remaining = readableTime(remainingTime); +</script> + +<div class="h-entry" title={$_('topic.title')}> + <h1 class="p-name">{topic.title}</h1> + <aside class="topic-meta" title={$_('topic.metadata_title')}> + {#if topic.forum} + <span class="topic-location"> + {$_('topic.category_location')} + <a href="/f/{topic.forum.id}" class="p-category"> + {topic.forum.glyph} {$_(topic.forum.label)} + </a>. + </span> + {/if} + <span class="topic-ttl"> + <a class="u-url u-uid" title={$_('topic.permalink_title')} href="/t/{topic.id}"> + ({$_('topic.remaining_time', { + values: { remaining: $_(remaining.label, { values: { count: remaining.count } }) } + })}) + </a>. + </span> + </aside> + {#if topic.tags.length > 0} + <aside class="topic-tags" title={$_('topic.tags_title')}> + {$_('topic.tags_location')} + {#each topic.tags as tag} + <a href="/g/{tag.id}" class="p-category"> + {tag.id}<span class="tag-weight">({tag.weight})</span> + </a>{' '} + {/each} + </aside> + {/if} + {#each topic.posts as post, index} + <Post {post} {index} count={topic.posts.length} /> + {/each} +</div> diff --git a/src/lib/components/topic/topic.test.ts b/src/lib/components/topic/topic.test.ts new file mode 100644 index 0000000..985ca72 --- /dev/null +++ b/src/lib/components/topic/topic.test.ts @@ -0,0 +1,168 @@ +/** + * @jest-environment jsdom + */ + +import '@testing-library/jest-dom/extend-expect'; + +import { addMessages } from 'svelte-i18n'; + +import { cleanup, render } from '@testing-library/svelte'; +import '$lib/i18n'; + +import Topic from './topic.svelte'; + +const internals = { + results: null, + basicTopic: { + id: 'b1a4f8d1-4d16-4872-b391-fda6a0e9012d', + title: 'I sure am a test topic', + ttl: 160 * 1000, + updated_at: Date.now(), + forum: { + id: 'diversion', + glyph: '⏃', + label: 'test_forums.diversion' + }, + tags: [ + { + id: 'fish', + weight: 40 + }, + { + id: 'statue', + weight: 5 + } + ], + posts: [ + { + id: '413a74db-9473-4bac-8698-da9452c05854', + text: 'This is the first post', + created_at: Date.UTC(1999, 7, 1, 8, 8, 2, 111).valueOf(), + author: { + handle: 'past_user', + id: 'c76d3e51-76ac-4e84-a1b2-2eee9abd68b3' + } + }, + { + id: '821ff177-5250-406f-9431-1a8097b35430', + text: 'This response came later', + created_at: Date.UTC(2038, 1, 2, 3, 4, 6, 789).valueOf(), + author: { + handle: 'future_user', + id: 'cb9307cb-77e9-4c55-bbe7-dbbf88737358' + } + } + ] + }, + topicWithoutForum: { + id: '9715e9ee-0d63-4b50-b613-826ef2791728', + title: 'This topic, no forums', + ttl: 160 * 1000, + updated_at: Date.now(), + tags: [ + { + id: 'cauliflower', + weight: 33 + } + ], + posts: [] + } +}; + +describe('Topic component', () => { + + beforeAll(() => { + + addMessages('en', { + 'test_forums.diversion': 'Diversion' + }); + }); + + beforeEach(() => { + + internals.results = render(Topic, { props: { + topic: internals.basicTopic + } }); + }); + + test('Should show the topic title', () => { + + expect(internals.results.getByText('I sure am a test topic')) + .toBeVisible(); + }); + test('Should display remaining time in readable format', () => { + + expect(internals.results.getByText(/2 minutes remaining/)) + .toBeVisible(); + }); + test('Remaining time should be a permalink to the topic', () => { + + expect(internals.results.getByText(/2 minutes remaining/).closest('a')) + .toHaveAttribute('href', '/t/b1a4f8d1-4d16-4872-b391-fda6a0e9012d'); + }); + + test('Should show text for all posts', () => { + + expect(internals.results.getByText('This is the first post')) + .toBeVisible(); + expect(internals.results.getByText('This response came later')) + .toBeVisible(); + }); + + test('Should send index and count to posts', () => { + + expect(internals.results.getByTitle('Post 1 of 2 by past_user')) + .toBeVisible(); + expect(internals.results.getByTitle('Post 2 of 2 by future_user')) + .toBeVisible(); + }); + + describe('Forum link', () => { + + test('Should show forum if the post has one', () => { + + expect(internals.results.getByText(/^\s*⏃\s*Diversion\s*$/)) + .toBeVisible(); + }); + + test('Forum text should be a permalink to the forum', () => { + + expect(internals.results.getByText(/^\s*⏃\s*Diversion\s*$/).closest('a')) + .toHaveAttribute('href', '/f/diversion'); + }); + + test('Should not show forum if the post doesn\'t have one', () => { + + cleanup(); + internals.results = render(Topic, { props: { + topic: internals.topicWithoutForum + } }); + + expect(internals.results.queryByText(/^\s*⏃\s*Diversion\s*$/)) + .toBe(null); + }); + }); + + describe('Tag listing', () => { + + test('Should show topic tags', () => { + + expect(internals.results.getByText('fish')) + .toBeVisible(); + expect(internals.results.getByText('fish')) + .toHaveTextContent('fish(40)'); + expect(internals.results.getByText('statue')) + .toBeVisible(); + expect(internals.results.getByText('statue')) + .toHaveTextContent('statue(5)'); + }); + + test('Tag text should be a permalink to the tag', () => { + + expect(internals.results.getByText('fish').closest('a')) + .toHaveAttribute('href', '/g/fish'); + expect(internals.results.getByText('statue').closest('a')) + .toHaveAttribute('href', '/g/statue'); + }); + }); +}); |