From 45b535f11f511f7460257d526de9e925b38ad009 Mon Sep 17 00:00:00 2001 From: deetz99 Date: Thu, 11 Jul 2024 09:14:10 -0700 Subject: [PATCH 1/9] fix link --- web/site/content/en-CA/products/br/overview.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/site/content/en-CA/products/br/overview.md b/web/site/content/en-CA/products/br/overview.md index 4e290c7a..83517e5b 100644 --- a/web/site/content/en-CA/products/br/overview.md +++ b/web/site/content/en-CA/products/br/overview.md @@ -74,7 +74,7 @@ All data with times are in UTC, both submitted and retrieved via the API. These ## Additional Resources -- Refer to the BC Gov site to answer any business rule related questions including Fees +- Refer to the BC Gov site to answer any business rule related questions including Fees - Refer to the BC Registry site to open an account and see all the Registry services. From ee1540d572e9893a0793c2a77dd4212f8f721332 Mon Sep 17 00:00:00 2001 From: deetz99 Date: Thu, 11 Jul 2024 11:49:21 -0700 Subject: [PATCH 2/9] test useDocPageData composable --- web/site/app/composables/docPageData.ts | 8 +-- .../unit/composables/docPageData.test.ts | 71 +++++++++++++++++++ 2 files changed, 73 insertions(+), 6 deletions(-) create mode 100644 web/site/app/tests/unit/composables/docPageData.test.ts diff --git a/web/site/app/composables/docPageData.ts b/web/site/app/composables/docPageData.ts index d5a95d5b..d4fe6483 100644 --- a/web/site/app/composables/docPageData.ts +++ b/web/site/app/composables/docPageData.ts @@ -40,16 +40,12 @@ export function useDocPageData () { // update data when locale or route changes watch([locale, routeWithoutLocale], async () => { await initDocPageData() - }) + }, { immediate: true }) // return current page data table of contents const tocLinks = computed(() => docPageData.value?.body?.toc?.links ?? []) const currentDir = computed(() => docPageData.value?._path) - onMounted(() => { - initDocPageData() - }) - - return { docPageData, tocLinks, currentDir, createPageHead } + return { docPageData, tocLinks, currentDir, createPageHead, initDocPageData } } diff --git a/web/site/app/tests/unit/composables/docPageData.test.ts b/web/site/app/tests/unit/composables/docPageData.test.ts new file mode 100644 index 00000000..4d2289d2 --- /dev/null +++ b/web/site/app/tests/unit/composables/docPageData.test.ts @@ -0,0 +1,71 @@ +import { describe, it, expect, vi, beforeEach } from 'vitest' +import { mockNuxtImport } from '@nuxt/test-utils/runtime' +import { useDocPageData } from '#imports' + +mockNuxtImport('useI18n', () => { + return () => { + return { locale: ref('en') } + } +}) + +mockNuxtImport('useRoute', () => { + return () => ( + { + path: '/en-CA/products', + meta: { + layout: 'docs' + } + } + ) +}) + +const queryContentMockData = { + _path: '/products/test', + _dir: 'get-started', + title: 'Test Title', + body: { toc: { links: [{ id: '1', text: 'Introduction', href: '#introduction' }] } } +} + +const { queryContentMock } = vi.hoisted(() => ({ + queryContentMock: vi.fn(() => ({ + where: vi.fn().mockReturnThis(), + findOne: vi.fn(() => Promise.resolve(queryContentMockData)) + })) +})) +mockNuxtImport('queryContent', () => queryContentMock) + +describe('useDocPageData', () => { + let composable: ReturnType + + beforeEach(async () => { + composable = useDocPageData() + // wait for promises to resolve + await new Promise(resolve => setTimeout(resolve, 0)) + }) + it('should return correct values based off route', () => { + // assert doc page data + expect(composable.docPageData.value).toEqual(queryContentMockData) + // assert toc links + expect(composable.tocLinks.value).toEqual(queryContentMockData.body.toc.links) + // assert current dir + expect(composable.currentDir.value).toEqual(queryContentMockData._path) + // assert generated page head + expect(composable.createPageHead()).toBe('Get Started - Test Title') + }) + + // TODO: figure out how to test the watcher reacting to route changes + it.skip('should handle route changes', async () => { + const { docPageData, currentDir, tocLinks, createPageHead } = useDocPageData() + // wait for promises to resolve + await new Promise(resolve => setTimeout(resolve, 0)) + + // assert doc page data + expect(docPageData.value).toEqual(queryContentMockData) + // assert toc links + expect(tocLinks.value).toEqual(queryContentMockData.body.toc.links) + // assert current dir + expect(currentDir.value).toEqual(queryContentMockData._path) + // assert generated page head + expect(createPageHead()).toBe('Get Started - Test Title') + }) +}) From 89177fa46a6d94baa906b0a5aec2c33b33dac015 Mon Sep 17 00:00:00 2001 From: deetz99 Date: Thu, 11 Jul 2024 13:45:16 -0700 Subject: [PATCH 3/9] sbcNav composable test --- .../app/tests/unit/composables/sbcNav.test.ts | 122 ++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 web/site/app/tests/unit/composables/sbcNav.test.ts diff --git a/web/site/app/tests/unit/composables/sbcNav.test.ts b/web/site/app/tests/unit/composables/sbcNav.test.ts new file mode 100644 index 00000000..dac8e508 --- /dev/null +++ b/web/site/app/tests/unit/composables/sbcNav.test.ts @@ -0,0 +1,122 @@ +import { describe, it, expect, vi, beforeEach } from 'vitest' +import { mockNuxtImport } from '@nuxt/test-utils/runtime' +import { useSbcNav } from '#imports' + +const localePathMock = vi.fn(path => `/en-CA${path}`) +mockNuxtImport('useLocalePath', () => { + return () => localePathMock +}) + +mockNuxtImport('useI18n', () => { + return () => { + return { + locale: ref('en'), + t: (key: any) => key + } + } +}) + +const routeRef = ref({ path: '/en-CA/products' }) +mockNuxtImport('useRoute', () => { + return () => routeRef.value +}) + +mockNuxtImport('useRouter', () => { + return () => ({ + isReady: vi.fn(() => Promise.resolve()) + }) +}) + +describe('useSbcNav', () => { + let composable: ReturnType + + beforeEach(() => { + vi.clearAllMocks() + composable = useSbcNav() + }) + + it('should return main links', () => { + const { mainLinks } = composable + + expect(mainLinks.value).toEqual([ + { + icon: 'i-mdi-home', + label: 'btn.sbcConnect', + to: '/en-CA/' + }, + { + icon: 'i-mdi-database', + label: 'btn.products', + to: '/en-CA/products' + }, + { + icon: 'i-mdi-book-open-variant', + label: 'Docs', + to: '/en-CA/products/get-started/account-setup' + } + ]) + }) + + it('should return loggedInUserOptions', () => { + const { loggedInUserOptions } = composable + + expect(loggedInUserOptions.value).toEqual([ + [ + { + label: 'Account', + slot: 'account', + disabled: true + }, + { + label: 'Log out', + icon: 'i-mdi-logout', + click: expect.any(Function) + } + ] + ]) + }) + + it('should return loggedOutUserOptions', () => { + const { loggedOutUserOptions } = composable + + expect(loggedOutUserOptions.value).toEqual([ + [ + { + label: 'Log in', + to: '/en-CA/sbc/auth/login', + icon: 'i-mdi-login' + }, + { + label: 'Create Account', + icon: 'i-mdi-account-plus' + } + ] + ]) + }) + + it('should open mobile nav', () => { + const { openMobileNav, mobileNavRef } = composable + expect(mobileNavRef.value).toBe(false) + openMobileNav() + expect(mobileNavRef.value).toBe(true) + }) + + it('should close mobile nav', async () => { + const { closeMobileNav, mobileNavRef } = composable + + mobileNavRef.value = true + await closeMobileNav() + expect(mobileNavRef.value).toBe(false) + }) + + // TODO: figure out how to test the watcher reacting to route changes + it.skip('should close mobile nav on route change', async () => { + const { mobileNavRef } = composable + mobileNavRef.value = true + expect(mobileNavRef.value).toBe(true) + routeRef.value = { path: '/en-CA/new-path' } + await nextTick() + + expect(mobileNavRef.value).toBe(false) + }) +}) From db25104fbce61e87318b1adb82401e9027987100 Mon Sep 17 00:00:00 2001 From: deetz99 Date: Thu, 11 Jul 2024 14:41:09 -0700 Subject: [PATCH 4/9] component tests --- .../components/SbcDocsProductCard.test.ts | 45 +++++++++++++++++++ .../components/SbcDocsTableOfContents.test.ts | 37 +++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 web/site/app/tests/unit/components/SbcDocsProductCard.test.ts create mode 100644 web/site/app/tests/unit/components/SbcDocsTableOfContents.test.ts diff --git a/web/site/app/tests/unit/components/SbcDocsProductCard.test.ts b/web/site/app/tests/unit/components/SbcDocsProductCard.test.ts new file mode 100644 index 00000000..f2aa3e6f --- /dev/null +++ b/web/site/app/tests/unit/components/SbcDocsProductCard.test.ts @@ -0,0 +1,45 @@ +import { describe, it, expect, vi } from 'vitest' +import { mockNuxtImport, mountSuspended } from '@nuxt/test-utils/runtime' +import { SbcDocsProductCard } from '#components' +import { enI18n } from '~/tests/mocks/i18n' + +const { navigateToMock } = vi.hoisted(() => ({ navigateToMock: vi.fn() })) +mockNuxtImport('navigateTo', () => navigateToMock) + +describe('SbcDocsProductCard', () => { + const props = { + name: 'Test Product', + description: 'This is a test product', + badge: 'New', + bulletPoints: ['Feature 1', 'Feature 2'], + directory: 'test-product' + } + + it('renders', async () => { + const wrapper = await mountSuspended(SbcDocsProductCard, { + props, + global: { + plugins: [enI18n] + } + }) + + expect(wrapper.find('[data-testid="product-card"]').exists()).toBe(true) + expect(wrapper.text()).toContain(props.name) + expect(wrapper.text()).toContain(props.description) + expect(wrapper.text()).toContain(props.badge) + expect(wrapper.text()).toContain(props.bulletPoints[0]) + expect(wrapper.text()).toContain(props.bulletPoints[1]) + }) + + it('navigates when clicked', async () => { + const wrapper = await mountSuspended(SbcDocsProductCard, { + props, + global: { + plugins: [enI18n] + } + }) + + await wrapper.trigger('click') + expect(navigateTo).toHaveBeenCalledWith('/en-CA/products/test-product/overview') + }) +}) diff --git a/web/site/app/tests/unit/components/SbcDocsTableOfContents.test.ts b/web/site/app/tests/unit/components/SbcDocsTableOfContents.test.ts new file mode 100644 index 00000000..8fca3920 --- /dev/null +++ b/web/site/app/tests/unit/components/SbcDocsTableOfContents.test.ts @@ -0,0 +1,37 @@ +import { describe, it, expect } from 'vitest' +import { mountSuspended } from '@nuxt/test-utils/runtime' +import { SbcDocsTableOfContents } from '#components' + +describe('TableOfContents', () => { + const props = { + tocLinks: [ + { id: 'section-1', text: 'Section 1', children: [], depth: 1 }, + { id: 'section-2', text: 'Section 2', children: [{ id: 'section-2-1', text: 'Section 2.1', depth: 2 }], depth: 1 } + ], + currentDir: '/docs', + activeTocId: 'section-1', + hideLabel: false + } + + it('renders', async () => { + const wrapper = await mountSuspended(SbcDocsTableOfContents, { + props + }) + + expect(wrapper.find('nav[aria-label="table of contents"]').exists()).toBe(true) + expect(wrapper.text()).toContain('Table of Contents') + expect(wrapper.text()).toContain('Section 1') + expect(wrapper.text()).toContain('Section 2') + expect(wrapper.text()).toContain('Section 2.1') + }) + + it('highlights the active link', async () => { + const wrapper = await mountSuspended(SbcDocsTableOfContents, { + props + }) + + const activeLink = wrapper.find('.text-primary-500') + expect(activeLink.exists()).toBe(true) + expect(activeLink.text()).toBe('Section 1') + }) +}) From ccf726fa0943ad4b6cd3e188a54a1b5fed450f1f Mon Sep 17 00:00:00 2001 From: deetz99 Date: Thu, 11 Jul 2024 15:00:28 -0700 Subject: [PATCH 5/9] organize e2e tests --- .../components/Sbc/Docs/SideNavigation.vue | 2 +- .../e2e/{ => journeys}/login-flow.test.ts | 6 +++--- .../e2e/{ => pages}/all-products-page.test.ts | 19 +++++++------------ .../e2e/{ => pages}/dashboard-page.test.ts | 2 +- .../tests/e2e/{ => pages}/docs-page.test.ts | 18 +++++++----------- .../tests/e2e/{ => pages}/home-page.test.ts | 16 ++++++++-------- .../tests/e2e/{ => pages}/tos-page.test.ts | 2 +- web/site/playwright.config.ts | 2 +- 8 files changed, 29 insertions(+), 38 deletions(-) rename web/site/app/tests/e2e/{ => journeys}/login-flow.test.ts (82%) rename web/site/app/tests/e2e/{ => pages}/all-products-page.test.ts (77%) rename web/site/app/tests/e2e/{ => pages}/dashboard-page.test.ts (94%) rename web/site/app/tests/e2e/{ => pages}/docs-page.test.ts (74%) rename web/site/app/tests/e2e/{ => pages}/home-page.test.ts (94%) rename web/site/app/tests/e2e/{ => pages}/tos-page.test.ts (93%) diff --git a/web/site/app/components/Sbc/Docs/SideNavigation.vue b/web/site/app/components/Sbc/Docs/SideNavigation.vue index e2a40a8f..939e3560 100644 --- a/web/site/app/components/Sbc/Docs/SideNavigation.vue +++ b/web/site/app/components/Sbc/Docs/SideNavigation.vue @@ -4,7 +4,7 @@ defineProps<{ }>() diff --git a/web/site/app/tests/e2e/login-flow.test.ts b/web/site/app/tests/e2e/journeys/login-flow.test.ts similarity index 82% rename from web/site/app/tests/e2e/login-flow.test.ts rename to web/site/app/tests/e2e/journeys/login-flow.test.ts index 7be32fd4..8c4b3f51 100644 --- a/web/site/app/tests/e2e/login-flow.test.ts +++ b/web/site/app/tests/e2e/journeys/login-flow.test.ts @@ -1,6 +1,6 @@ import { test } from '@playwright/test' -test('test', async ({ page }) => { +test.skip('test', async ({ page }) => { await page.goto('http://localhost:3467/en-CA') await page.getByRole('link', { name: 'Dashboard' }).click() const page1Promise = page.waitForEvent('popup') @@ -9,9 +9,9 @@ test('test', async ({ page }) => { await page1.getByLabel('Log in with Test with').click() await page1.getByLabel('Email or username').click() await page1.getByLabel('Email or username').press('CapsLock') - await page1.getByLabel('Email or username').fill('BCREG4000') + await page1.getByLabel('Email or username').fill('') // username await page1.getByLabel('Password').click() - await page1.getByLabel('Password').fill('98940000') + await page1.getByLabel('Password').fill('') // password await page1.getByLabel('Password').press('Tab') await page1.getByRole('button', { name: 'Continue' }).click() await page.goto('http://localhost:3467/en-CA') diff --git a/web/site/app/tests/e2e/all-products-page.test.ts b/web/site/app/tests/e2e/pages/all-products-page.test.ts similarity index 77% rename from web/site/app/tests/e2e/all-products-page.test.ts rename to web/site/app/tests/e2e/pages/all-products-page.test.ts index 14b2d77a..540832ee 100644 --- a/web/site/app/tests/e2e/all-products-page.test.ts +++ b/web/site/app/tests/e2e/pages/all-products-page.test.ts @@ -6,22 +6,17 @@ test.describe('products page', () => { await page.goto('/en-CA/products') }) - test('page contents', async ({ page }) => { - const h1 = await page.textContent('h1') - expect(h1).toBe('All Products') - await expect(page.getByTestId('product-card')).toHaveCount(7) // there should be 7 product cards - }) - - test('accessibility', async ({ page }) => { - await page - .getByText('All Products') - .first() - .click() // wait for page load before runnign a11y checks? fails without this - + test.afterEach(async ({ page }) => { const a11yResults = await new AxeBuilder({ page }) .exclude('#locale-select-dropdown') // headless ui dropdown fails the axe check .analyze() expect(a11yResults.violations).toEqual([]) }) + + test('page contents', async ({ page }) => { + const h1 = await page.textContent('h1') + expect(h1).toBe('All Products') + await expect(page.getByTestId('product-card')).toHaveCount(7) // there should be 7 product cards + }) }) diff --git a/web/site/app/tests/e2e/dashboard-page.test.ts b/web/site/app/tests/e2e/pages/dashboard-page.test.ts similarity index 94% rename from web/site/app/tests/e2e/dashboard-page.test.ts rename to web/site/app/tests/e2e/pages/dashboard-page.test.ts index d1bebb9e..1300cf95 100644 --- a/web/site/app/tests/e2e/dashboard-page.test.ts +++ b/web/site/app/tests/e2e/pages/dashboard-page.test.ts @@ -1,7 +1,7 @@ import { test, expect } from '@playwright/test' import AxeBuilder from '@axe-core/playwright' -test.describe('dashboard page', () => { +test.describe.skip('dashboard page', () => { test.beforeEach(async ({ page }) => { await page.goto('/en-CA/sbc/dashboard') }) diff --git a/web/site/app/tests/e2e/docs-page.test.ts b/web/site/app/tests/e2e/pages/docs-page.test.ts similarity index 74% rename from web/site/app/tests/e2e/docs-page.test.ts rename to web/site/app/tests/e2e/pages/docs-page.test.ts index 25d9253e..517d3b8f 100644 --- a/web/site/app/tests/e2e/docs-page.test.ts +++ b/web/site/app/tests/e2e/pages/docs-page.test.ts @@ -6,21 +6,17 @@ test.describe('docs page', () => { await page.goto('/en-CA/products/get-started') }) - test('page contents', async ({ page }) => { - const h1 = await page.textContent('h1') - expect(h1).toBe('Account Setup') - }) - - test('accessibility', async ({ page }) => { - await page - .getByText('Account Setup') - .first() - .click() // wait for page load before runnign a11y checks? fails without this - + test.afterEach(async ({ page }) => { const a11yResults = await new AxeBuilder({ page }) .exclude('#locale-select-dropdown') // headless ui dropdown fails the axe check .analyze() expect(a11yResults.violations).toEqual([]) }) + + test('page contents', async ({ page }) => { + const h1 = await page.textContent('h1') + expect(h1).toBe('Account Setup') + expect(page.getByTestId('docs-side-navigation')).toBeDefined() + }) }) diff --git a/web/site/app/tests/e2e/home-page.test.ts b/web/site/app/tests/e2e/pages/home-page.test.ts similarity index 94% rename from web/site/app/tests/e2e/home-page.test.ts rename to web/site/app/tests/e2e/pages/home-page.test.ts index 962e8417..02257d9f 100644 --- a/web/site/app/tests/e2e/home-page.test.ts +++ b/web/site/app/tests/e2e/pages/home-page.test.ts @@ -6,6 +6,14 @@ test.describe('home page', () => { await page.goto('/en-CA') }) + test.afterEach(async ({ page }) => { + const a11yResults = await new AxeBuilder({ page }) + .exclude('#locale-select-dropdown') // headless ui dropdown fails the axe check + .analyze() + + expect(a11yResults.violations).toEqual([]) + }) + test('page contents', async ({ page }) => { const h1 = await page.textContent('h1') const p = await page.textContent('p') @@ -14,12 +22,4 @@ test.describe('home page', () => { expect(h1).toBe('BC Registries API Gateway') expect(p).toBe('Welcome to the BC Registries API Gateway! Access API information for all BC Registries services here.') }) - - test('accessibility', async ({ page }) => { - const a11yResults = await new AxeBuilder({ page }) - .exclude('#locale-select-dropdown') // headless ui dropdown fails the axe check - .analyze() - - expect(a11yResults.violations).toEqual([]) - }) }) diff --git a/web/site/app/tests/e2e/tos-page.test.ts b/web/site/app/tests/e2e/pages/tos-page.test.ts similarity index 93% rename from web/site/app/tests/e2e/tos-page.test.ts rename to web/site/app/tests/e2e/pages/tos-page.test.ts index 1d7dfdbb..a75de72c 100644 --- a/web/site/app/tests/e2e/tos-page.test.ts +++ b/web/site/app/tests/e2e/pages/tos-page.test.ts @@ -1,7 +1,7 @@ import { test, expect } from '@playwright/test' import AxeBuilder from '@axe-core/playwright' -test.describe('terms of use page', () => { +test.describe.skip('terms of use page', () => { test.beforeEach(async ({ page }) => { await page.goto('/en-CA/sbc/tos') }) diff --git a/web/site/playwright.config.ts b/web/site/playwright.config.ts index 2f5c0d8b..b09342d2 100644 --- a/web/site/playwright.config.ts +++ b/web/site/playwright.config.ts @@ -16,7 +16,7 @@ const devicesToTest = [ ] satisfies Array export default defineConfig({ - testDir: './tests/e2e', + testDir: './app/tests/e2e', reporter: 'line', // Fail the build on CI if you accidentally left test.only in the source code. forbidOnly: !!process.env.CI, From a5627dc60e969dae6a9d32df89ac1a224e8abc9c Mon Sep 17 00:00:00 2001 From: deetz99 Date: Thu, 11 Jul 2024 15:06:37 -0700 Subject: [PATCH 6/9] fix types --- .../app/components/Sbc/Dashboard/Modal.vue | 2 +- web/site/app/tests/setup/i18n.ts | 2 +- web/site/app/utils/createContentNav.ts | 2 +- web/site/server/api/reg-search.ts | 27 ------------------- 4 files changed, 3 insertions(+), 30 deletions(-) delete mode 100644 web/site/server/api/reg-search.ts diff --git a/web/site/app/components/Sbc/Dashboard/Modal.vue b/web/site/app/components/Sbc/Dashboard/Modal.vue index cc63079a..8039aacb 100644 --- a/web/site/app/components/Sbc/Dashboard/Modal.vue +++ b/web/site/app/components/Sbc/Dashboard/Modal.vue @@ -43,7 +43,7 @@ watch(modalOpen, () => { {{ content }}