diff --git a/frontend/src/components/__tests__/PageHeader.spec.ts b/frontend/src/components/__tests__/PageHeader.spec.ts index f0f04c4e..3eb8eb28 100644 --- a/frontend/src/components/__tests__/PageHeader.spec.ts +++ b/frontend/src/components/__tests__/PageHeader.spec.ts @@ -1,6 +1,5 @@ import { afterEach, describe, expect, it, vi } from 'vitest' import { nextTick } from 'vue' -import { VMenu } from 'vuetify/components' import SearchBar from '@/components/SearchBar.vue' import { setupMountedComponents } from '@/lib/testUtils' @@ -9,6 +8,7 @@ import { StoreState } from '@/stores/misc' import PageHeader from '../PageHeader.vue' +// Test data const geneData = { storeState: 'active', geneSymbol: 'BRCA1', @@ -27,25 +27,29 @@ describe.concurrent('PageHeader', async () => { }) it('renders the gene symbol and nav links', async () => { + // arrange: const { wrapper } = await setupMountedComponents( { component: PageHeader }, { initialStoreState: geneData } ) - const store = useGeneInfoStore() store.storeState = StoreState.Active store.hgncId = geneData.geneSymbol store.geneInfo = JSON.parse(JSON.stringify(geneData.geneInfo)) + // act: nothing, only test rendering + + // assert: const logo = wrapper.find('#logo') - const menu = wrapper.findComponent(VMenu) + const menu = wrapper.findComponent({'name': 'VMenu'}) expect(logo.exists()).toBe(true) expect(menu.exists()).toBe(true) }) it('renders the search bar', async () => { + // arrange: const { wrapper } = await setupMountedComponents( { component: PageHeader }, { @@ -57,12 +61,16 @@ describe.concurrent('PageHeader', async () => { store.hgncId = geneData.geneSymbol store.geneInfo = JSON.parse(JSON.stringify(geneData.geneInfo)) + // act: nothing, only test rendering + + // assert: // search bar value is updated to "HGNC:1100" const searchBar = wrapper.findComponent(SearchBar) expect(searchBar.exists()).toBe(true) }) it.skip('correctly emits search', async () => { + // arrange: // Mock fetch global.fetch = vi.fn((): any => Promise.resolve({ ok: true, json: () => Promise.resolve({ success: false, value: null }) }) @@ -79,6 +87,7 @@ describe.concurrent('PageHeader', async () => { store.hgncId = geneData.geneSymbol store.geneInfo = JSON.parse(JSON.stringify(geneData.geneInfo)) + // act: // search bar value is updated to "HGNC:1100" const searchBar = wrapper.findComponent(SearchBar) await searchBar.setValue('HGNC:1100', 'searchTerm') @@ -90,6 +99,7 @@ describe.concurrent('PageHeader', async () => { await nextTick() + // assert: expect(router.push).toHaveBeenCalledOnce() expect(router.push).toHaveBeenCalledWith({ name: 'gene-details', diff --git a/frontend/src/components/__tests__/SearchBar.spec.ts b/frontend/src/components/__tests__/SearchBar.spec.ts index 92673a70..6f13f91c 100644 --- a/frontend/src/components/__tests__/SearchBar.spec.ts +++ b/frontend/src/components/__tests__/SearchBar.spec.ts @@ -12,6 +12,7 @@ describe.concurrent('SearchBar.vue', () => { }) it('renders the search bar with the correct default props', async () => { + // arrange: const { wrapper } = await setupMountedComponents( { component: SearchBar }, { @@ -22,6 +23,9 @@ describe.concurrent('SearchBar.vue', () => { } ) + // act: nothing, only test rendering + + // assert: const textField = wrapper.find('.v-text-field') const genomeReleaseMenu = wrapper.find('.genome-release-menu') const searchButton = wrapper.find('.start-search') @@ -34,6 +38,7 @@ describe.concurrent('SearchBar.vue', () => { }) it('correctly inputs data', async () => { + // arrange: const { wrapper } = await setupMountedComponents( { component: SearchBar }, { @@ -44,21 +49,21 @@ describe.concurrent('SearchBar.vue', () => { } ) + // act: const textField = wrapper.find('.search-term input') as any expect(textField.exists()).toBe(true) await textField.setValue('test') expect(textField.element.value).toBe('test') + // assert: const select = wrapper.find('.genome-release-menu') as any expect(select.exists()).toBe(true) - const genomeReleaseMenu = wrapper.findComponent('.genome-release-menu') as any expect(genomeReleaseMenu.exists()).toBe(true) - await genomeReleaseMenu.trigger('click') - await nextTick() }) it('correctly emits search', async () => { + // arrange: // we make `DottyClient.toSpdi` return null / fail vi.spyOn(DottyClient.prototype, 'toSpdi').mockResolvedValue(null) @@ -72,17 +77,41 @@ describe.concurrent('SearchBar.vue', () => { } ) + // act: // search bar values are updated const searchBar = wrapper.findComponent(SearchBar) expect(searchBar.exists()).toBe(true) await searchBar.setValue('HGNC:1100', 'searchTerm') await searchBar.setValue('grch37', 'genomeRelease') + + // assert: expect(searchBar.emitted()).toHaveProperty('update:searchTerm') expect(searchBar.emitted()).toHaveProperty('update:genomeRelease') + }) + + it('correctly clicks search button', async () => { + // arrange: + // we make `DottyClient.toSpdi` return null / fail + vi.spyOn(DottyClient.prototype, 'toSpdi').mockResolvedValue(null) + + const { wrapper } = await setupMountedComponents( + { component: SearchBar }, + { + props: { + searchTerm: 'BRCA1', + genomeRelease: 'grch37' + } + } + ) + + // act: + const searchBar = wrapper.findComponent(SearchBar) const searchButton = searchBar.findComponent('button.start-search') as any expect(searchButton.exists()).toBe(true) await searchButton.trigger('click') await nextTick() + + // assert: expect(searchBar.emitted()).toHaveProperty('clickSearch') }) }) diff --git a/frontend/src/components/__tests__/UserProfileButton.spec.ts b/frontend/src/components/__tests__/UserProfileButton.spec.ts index 112f2654..9fe02527 100644 --- a/frontend/src/components/__tests__/UserProfileButton.spec.ts +++ b/frontend/src/components/__tests__/UserProfileButton.spec.ts @@ -6,6 +6,7 @@ import { type UserData, useUserStore } from '@/stores/user' import UserProfileButton from '../UserProfileButton.vue' +// Test data const adminUser: UserData = { id: '2c0a153e-5e8c-11ee-8c99-0242ac120002', email: 'admin@example.com', @@ -24,6 +25,7 @@ const adminUser: UserData = { describe.concurrent('UserProfileButton', () => { it('displays Login button without any user', async () => { + // arrange: const { wrapper } = await setupMountedComponents( { component: UserProfileButton }, { @@ -34,7 +36,10 @@ describe.concurrent('UserProfileButton', () => { } } ) + + // act: nothing, only test rendering + // assert: const loginButton = wrapper.findComponent('#login') expect(loginButton.exists()).toBe(true) const logoutButton = wrapper.findComponent('#profile') @@ -42,6 +47,7 @@ describe.concurrent('UserProfileButton', () => { }) it('displays Profile button with a user', async () => { + // arrange: const { wrapper } = await setupMountedComponents( { component: UserProfileButton }, { @@ -53,6 +59,9 @@ describe.concurrent('UserProfileButton', () => { } ) + // act: nothing, only test rendering + + // assert: const loginButton = wrapper.findComponent('#login') expect(loginButton.exists()).toBe(false) const logoutButton = wrapper.findComponent('#profile') @@ -60,6 +69,7 @@ describe.concurrent('UserProfileButton', () => { }) it('switches from Login to Profile button when store changes', async () => { + // arrange: // Note that we use an `async` test here as we need `await nextTick()` for the DOM // update to bubble through when updating the state property. const { wrapper } = await setupMountedComponents( @@ -73,6 +83,7 @@ describe.concurrent('UserProfileButton', () => { } ) + // act: let loginButton = wrapper.findComponent('#login') expect(loginButton.exists()).toBe(true) let logoutButton = wrapper.findComponent('#profile') @@ -83,6 +94,7 @@ describe.concurrent('UserProfileButton', () => { await nextTick() + // assert: loginButton = wrapper.findComponent('#login') expect(loginButton.exists()).toBe(false) logoutButton = wrapper.findComponent('#profile') diff --git a/frontend/src/components/__tests__/VegaPlot.spec.ts b/frontend/src/components/__tests__/VegaPlot.spec.ts index 4544193e..1a5d4f9c 100644 --- a/frontend/src/components/__tests__/VegaPlot.spec.ts +++ b/frontend/src/components/__tests__/VegaPlot.spec.ts @@ -1,9 +1,10 @@ -import { describe, it } from 'vitest' +import { describe, expect, it } from 'vitest' import { setupMountedComponents } from '@/lib/testUtils' import VegaPlot from '../VegaPlot.vue' +// Test data const vegaData = [ { tissue: 'Adipose Tissue', @@ -54,8 +55,9 @@ const vegaLayer = [ describe.concurrent('VegaPlot', async () => { // Skipping tests due to error with vega-embed // DataCloneError: # could not be cloned. - it.skip('renders the VegaPlot info', async () => { - await setupMountedComponents( + it('renders the VegaPlot info', async () => { + // arrange: + const { wrapper } = await setupMountedComponents( { component: VegaPlot }, { props: { @@ -72,5 +74,11 @@ describe.concurrent('VegaPlot', async () => { } } ) + // act: nothing to do + + // assert: + expect(wrapper.text()).toContain('Save as PNG') + expect(wrapper.text()).toContain('View Source') + expect(wrapper.text()).toContain('Open in Vega Editor') }) })