From 9268ab5925531420624a9705c5348787ea4f0260 Mon Sep 17 00:00:00 2001 From: William Volin Date: Mon, 4 Nov 2024 10:42:40 -0700 Subject: [PATCH] feat: adds landing page scaffolding (#641) * feat: adds landing page scaffolding chore: adds tests * fix: properly use key on landing leaderboard * fix: responsive design for landing page * feat: use real leaderboards endpoint and add some cursory styling chore: undo unneeded shared interface chore: remove old todo chore: add test to LandingLeaderboards * feat: adds games above games list * fix: leaderboard list padding * fix: leaderboard list spacing and links chore: remove unused code chore: remove unused code * fix: update link underline and color * fix: revert tailwind color extensions * chore: use self closing tag * chore: remove mocks for landing leaderboards test chore: fix * fun: clean up tests * fun: update expectations in Landing test --- components/blocks/Landing/Landing.test.ts | 22 +++++++ components/blocks/Landing/Landing.vue | 20 +++++++ .../blocks/Landing/LandingAbout.test.ts | 13 ++++ components/blocks/Landing/LandingAbout.vue | 44 ++++++++++++++ .../Landing/LandingLeaderboards.test.ts | 59 +++++++++++++++++++ .../blocks/Landing/LandingLeaderboards.vue | 33 +++++++++++ composables/api/index.ts | 1 + composables/api/useGetLeaderboards/index.ts | 40 +++++++++++++ .../useGetLeaderboards.test.ts | 21 +++++++ pages/board/[slug].vue | 1 + pages/index.test.ts | 6 +- pages/index.vue | 9 ++- 12 files changed, 259 insertions(+), 10 deletions(-) create mode 100644 components/blocks/Landing/Landing.test.ts create mode 100644 components/blocks/Landing/Landing.vue create mode 100644 components/blocks/Landing/LandingAbout.test.ts create mode 100644 components/blocks/Landing/LandingAbout.vue create mode 100644 components/blocks/Landing/LandingLeaderboards.test.ts create mode 100644 components/blocks/Landing/LandingLeaderboards.vue create mode 100644 composables/api/useGetLeaderboards/index.ts create mode 100644 composables/api/useGetLeaderboards/useGetLeaderboards.test.ts diff --git a/components/blocks/Landing/Landing.test.ts b/components/blocks/Landing/Landing.test.ts new file mode 100644 index 00000000..2cee0574 --- /dev/null +++ b/components/blocks/Landing/Landing.test.ts @@ -0,0 +1,22 @@ +import { mountSuspended } from '@nuxt/test-utils/runtime' +import Landing from './Landing.vue' +import LandingAbout from './LandingAbout.vue' +import LandingLeaderboards from './LandingLeaderboards.vue' + +const mockSuccessGetLeaderboards = vi.fn(() => Promise.resolve({ ok: true })) +vi.mock('lib/api/Leaderboards', () => ({ + Leaderboards: function Leaderboards() { + this.getLeaderboards = mockSuccessGetLeaderboards + }, +})) + +describe('Landing Component', () => { + it('should render without crashing', async () => { + const wrapper = await mountSuspended(Landing) + + expect(wrapper.isVisible()).toBe(true) + expect(wrapper.getComponent(LandingAbout).isVisible()).toBe(true) + expect(wrapper.getComponent(LandingLeaderboards).isVisible()).toBe(true) + expect(mockSuccessGetLeaderboards).toHaveBeenCalledOnce() + }) +}) diff --git a/components/blocks/Landing/Landing.vue b/components/blocks/Landing/Landing.vue new file mode 100644 index 00000000..8cf0ada4 --- /dev/null +++ b/components/blocks/Landing/Landing.vue @@ -0,0 +1,20 @@ + + + diff --git a/components/blocks/Landing/LandingAbout.test.ts b/components/blocks/Landing/LandingAbout.test.ts new file mode 100644 index 00000000..192a9e7e --- /dev/null +++ b/components/blocks/Landing/LandingAbout.test.ts @@ -0,0 +1,13 @@ +import { mountSuspended } from '@nuxt/test-utils/runtime' +import Landing from './LandingAbout.vue' + +describe('LandingAbout Component', () => { + it('should render without crashing', async () => { + const wrapper = await mountSuspended(Landing) + + expect(wrapper.isVisible()).toBe(true) + + const text = wrapper.getComponent('div#landing-about').text() + expect(text).toContain('About Leaderboards.gg') + }) +}) diff --git a/components/blocks/Landing/LandingAbout.vue b/components/blocks/Landing/LandingAbout.vue new file mode 100644 index 00000000..957975ca --- /dev/null +++ b/components/blocks/Landing/LandingAbout.vue @@ -0,0 +1,44 @@ + + + + + diff --git a/components/blocks/Landing/LandingLeaderboards.test.ts b/components/blocks/Landing/LandingLeaderboards.test.ts new file mode 100644 index 00000000..a74e0b38 --- /dev/null +++ b/components/blocks/Landing/LandingLeaderboards.test.ts @@ -0,0 +1,59 @@ +import { mountSuspended } from '@nuxt/test-utils/runtime' +import Landing from './LandingLeaderboards.vue' +import type { LeaderboardViewModel } from '~/lib/api/data-contracts' + +const games: LeaderboardViewModel[] = [ + { + id: 1, + name: 'Getting Over It With Bennet Foddy', + slug: 'slug-2', + info: null, + createdAt: '2024-11-02T22:11:08+0000', + updatedAt: '2024-11-02T22:11:08+0000', + deletedAt: null, + categories: [], + }, + { + id: 2, + name: 'Getting Over It With Bennet Foddy', + slug: 'slug-2', + info: null, + createdAt: '2024-11-02T22:11:08+0000', + updatedAt: '2024-11-02T22:11:08+0000', + deletedAt: null, + categories: [], + }, + { + id: 3, + name: 'Getting Over It With Bennet Foddy', + slug: 'slug-3', + info: null, + createdAt: '2024-11-02T22:11:08+0000', + updatedAt: '2024-11-02T22:11:08+0000', + deletedAt: null, + categories: [], + }, +] + +describe('LandingLeaderboards Component', () => { + afterEach(() => { + vi.restoreAllMocks() + }) + + it('should render without crashing', async () => { + const wrapper = await mountSuspended(Landing, { + props: { + leaderboards: games, + }, + }) + + expect(wrapper.isVisible()).toBe(true) + + wrapper + .getComponent('div#landing-leaderboards') + .findAllComponents('div') + .forEach((c, i) => { + expect(c.text()).toBe(games[i]) + }) + }) +}) diff --git a/components/blocks/Landing/LandingLeaderboards.vue b/components/blocks/Landing/LandingLeaderboards.vue new file mode 100644 index 00000000..d2deb002 --- /dev/null +++ b/components/blocks/Landing/LandingLeaderboards.vue @@ -0,0 +1,33 @@ + + diff --git a/composables/api/index.ts b/composables/api/index.ts index 008b1beb..27497ec7 100644 --- a/composables/api/index.ts +++ b/composables/api/index.ts @@ -1,6 +1,7 @@ export { default as useChangePassword } from './useChangePassword' export { default as useConfirmAccount } from './useConfirmAccount' export { default as useGetLeaderboardBySlug } from './useGetLeaderboardBySlug' +export { default as useGetLeaderboards } from './useGetLeaderboards' export { default as useGetUser } from './useGetUser' export { default as useLoginUser } from './useLoginUser' export { default as useLogoutUser } from './useLogoutUser' diff --git a/composables/api/useGetLeaderboards/index.ts b/composables/api/useGetLeaderboards/index.ts new file mode 100644 index 00000000..7eb394e8 --- /dev/null +++ b/composables/api/useGetLeaderboards/index.ts @@ -0,0 +1,40 @@ +import { ref } from 'vue' +import { + useApi, + type ApiResponse, + type optionalParameters, +} from 'composables/useApi' +import { Leaderboards } from 'lib/api/Leaderboards' +import type { LeaderboardViewModel } from 'lib/api/data-contracts' +import { useRuntimeConfig } from '#imports' + +export default async function useGetLeaderboards( + opts: optionalParameters = {}, +): Promise> { + const { onError, onOkay } = opts + const responseData = ref([ + { + categories: [], + id: -1, + name: '', + slug: '', + info: null, + createdAt: '', + updatedAt: null, + deletedAt: null, + }, + ]) + + const leaderboardClient = new Leaderboards({ + baseUrl: useRuntimeConfig().public.backendBaseUrl, + }) + + return await useApi( + async () => await leaderboardClient.getLeaderboards({}), + { + onError, + onOkay, + responseData, + }, + ) +} diff --git a/composables/api/useGetLeaderboards/useGetLeaderboards.test.ts b/composables/api/useGetLeaderboards/useGetLeaderboards.test.ts new file mode 100644 index 00000000..2b4ed631 --- /dev/null +++ b/composables/api/useGetLeaderboards/useGetLeaderboards.test.ts @@ -0,0 +1,21 @@ +import useGetLeaderboards from '.' + +const mockSuccessGetLeaderboards = vi.fn(() => Promise.resolve({ ok: true })) + +describe('useGetLeaderboard', () => { + describe('when everything is successful', () => { + const queryParams = {} + it('creates a GET request to fetch the a list of leaderboards', async () => { + vi.mock('lib/api/Leaderboards', () => ({ + Leaderboards: function Leaderboards() { + this.getLeaderboards = mockSuccessGetLeaderboards + }, + })) + + await useGetLeaderboards() + + expect(mockSuccessGetLeaderboards).toBeCalledTimes(1) + expect(mockSuccessGetLeaderboards).toBeCalledWith(queryParams) + }) + }) +}) diff --git a/pages/board/[slug].vue b/pages/board/[slug].vue index 38d7a678..588a1d58 100644 --- a/pages/board/[slug].vue +++ b/pages/board/[slug].vue @@ -1,4 +1,5 @@ +