-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Configure vitest with API and Pinia mocking #229
Changes from all commits
f50d128
b9e87ca
f5559b5
09af4fc
7fdd5d6
0636b5f
9a012d8
48be4cd
ea2c99e
a2ed261
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The mock response data and store data here is very large. My suggestion would be to, in future work, break these out into another file to quickly import with a helpful name. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,203 @@ | ||
import { Quasar } from 'quasar'; | ||
import { describe, expect, test, vi } from 'vitest'; | ||
import { createTestingPinia } from '@pinia/testing'; | ||
import { flushPromises, mount } from '@vue/test-utils'; | ||
|
||
import api, { AppMode, DeploymentFile, DeploymentFileType, ExclusionMatchSource, ServerType, useApi } from 'src/api'; | ||
import FilesToPublish from 'src/components/configurePublish/FilesToPublish.vue'; | ||
import { useDeploymentStore } from 'src/stores/deployment'; | ||
|
||
const fakeResponse: DeploymentFile = { | ||
id: '.', | ||
fileType: DeploymentFileType.DIRECTORY, | ||
base: 'fastapi-simple', | ||
exclusion: null, | ||
files: [ | ||
{ | ||
id: '.gitignore', | ||
fileType: DeploymentFileType.REGULAR, | ||
base: '.gitignore', | ||
exclusion: { | ||
source: ExclusionMatchSource.BUILT_IN, | ||
pattern: '.gitignore', | ||
filePath: '', | ||
line: 0 | ||
}, | ||
files: [], | ||
isDir: false, | ||
isEntrypoint: false, | ||
isFile: true, | ||
modifiedDatetime: '2023-09-19T10:20:06-07:00', | ||
rel: '.gitignore', | ||
size: 6, | ||
abs: '/Users/jordan/development/publishing-client/test/sample-content/fastapi-simple/.gitignore' | ||
}, | ||
{ | ||
id: 'manifest.json', | ||
fileType: DeploymentFileType.REGULAR, | ||
base: 'manifest.json', | ||
exclusion: { | ||
source: ExclusionMatchSource.BUILT_IN, | ||
pattern: 'manifest.json', | ||
filePath: '', | ||
line: 0 | ||
}, | ||
files: [], | ||
isDir: false, | ||
isEntrypoint: false, | ||
isFile: true, | ||
modifiedDatetime: '2023-08-18T11:56:15-07:00', | ||
rel: 'manifest.json', | ||
size: 552, | ||
abs: '/Users/jordan/development/publishing-client/test/sample-content/fastapi-simple/manifest.json' | ||
}, | ||
{ | ||
id: 'meta.yaml', | ||
fileType: DeploymentFileType.REGULAR, | ||
base: 'meta.yaml', | ||
exclusion: null, | ||
files: [], | ||
isDir: false, | ||
isEntrypoint: false, | ||
isFile: true, | ||
modifiedDatetime: '2023-08-02T15:41:24-07:00', | ||
rel: 'meta.yaml', | ||
size: 63, | ||
abs: '/Users/jordan/development/publishing-client/test/sample-content/fastapi-simple/meta.yaml' | ||
}, | ||
{ | ||
id: 'requirements.in', | ||
fileType: DeploymentFileType.REGULAR, | ||
base: 'requirements.in', | ||
exclusion: null, | ||
files: [], | ||
isDir: false, | ||
isEntrypoint: false, | ||
isFile: true, | ||
modifiedDatetime: '2023-08-02T15:41:24-07:00', | ||
rel: 'requirements.in', | ||
size: 124, | ||
abs: '/Users/jordan/development/publishing-client/test/sample-content/fastapi-simple/requirements.in' | ||
}, | ||
{ | ||
id: 'requirements.txt', | ||
fileType: DeploymentFileType.REGULAR, | ||
base: 'requirements.txt', | ||
exclusion: null, | ||
files: [], | ||
isDir: false, | ||
isEntrypoint: false, | ||
isFile: true, | ||
modifiedDatetime: '2023-08-02T15:41:24-07:00', | ||
rel: 'requirements.txt', | ||
size: 235, | ||
abs: '/Users/jordan/development/publishing-client/test/sample-content/fastapi-simple/requirements.txt' | ||
}, | ||
{ | ||
id: 'simple.py', | ||
fileType: DeploymentFileType.REGULAR, | ||
base: 'simple.py', | ||
exclusion: null, | ||
files: [], | ||
isDir: false, | ||
isEntrypoint: false, | ||
isFile: true, | ||
modifiedDatetime: '2023-08-02T15:41:24-07:00', | ||
rel: 'simple.py', | ||
size: 369, | ||
abs: '/Users/jordan/development/publishing-client/test/sample-content/fastapi-simple/simple.py' | ||
} | ||
], | ||
isDir: true, | ||
isEntrypoint: false, | ||
isFile: false, | ||
modifiedDatetime: '2023-09-19T10:20:06-07:00', | ||
rel: '.', | ||
size: 256, | ||
abs: '/Users/jordan/development/publishing-client/test/sample-content/fastapi-simple' | ||
}; | ||
|
||
vi.mock('src/api'); | ||
vi.mocked(useApi).mockReturnValue(api); | ||
Comment on lines
+120
to
+121
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This bit was extremely tricky.
So great we get a nice mock with no effort. However our API module has two exports that rely on each other:
and Vitest has no clue about this when it constructs its mock. So
Is here to recreate that relationship so both This can probbably be broken out into a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's a funny call when separating out the test data. I think it would be useful to have a way of having base test data which could be pulled in from an external file, but then also overlay specific test data changes on top of it, for a particular test. This can obviously be created organically as we go forward, but it would be good to outline a small pattern to use so we could all be consistent. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Completely agree. Having test data in an external file that we can override partially would be perfect. I think another PR introducing that pattern with another test would be a great next step. |
||
|
||
describe('description', () => { | ||
test('some test description', async() => { | ||
vi.mocked(api.files.get, { partial: true }).mockResolvedValue({ data: fakeResponse }); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also a bit tricky. Once the mocking was fixed this became pretty easy! The |
||
|
||
const wrapper = mount(FilesToPublish, { | ||
global: { | ||
plugins: [Quasar, createTestingPinia({ createSpy: vi.fn })] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Each time we mount we need to enable the |
||
} | ||
}); | ||
|
||
const deploymentStore = useDeploymentStore(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It seems a bit strange to me that we call this after we mount the component. I would think of this as part of the test setup, all available ahead of the component being mounted (at which time it would run through all of its normal behavior). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree. The Pinia docs don't explicitly say it, but in their examples always have the use store code under the mount 1. If we move it above we get an error:
Since the mount is actually creating the Pinia we need to do it first. I actually had the same reaction and tried moving it above when things weren't quite working wondering if that was a fix. Footnotes |
||
deploymentStore.deployment = { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. With the deployment store being so "mono" across all of our settings, we're definitely going to want to put something better in place so we're not always copying/pasting the state over and over. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 100% agree. I think it will look very similar to your proposal of importing things from an external file and overriding where necessary. In a follow-up PR introducing this will be important as soon as we have more than a single test. |
||
sourcePath: 'test/sample-content/fastapi-simple', | ||
target: { | ||
accountName: 'dogfood', | ||
serverType: ServerType.CONNECT, | ||
serverUrl: '', | ||
contentId: '', | ||
contentName: '', | ||
username: '', | ||
bundleId: null, | ||
deployedAt: null | ||
}, | ||
manifest: { | ||
version: 1, | ||
locale: '', | ||
metadata: { | ||
appmode: AppMode.PYTHON_FASTAPI, | ||
entrypoint: 'simple.py', | ||
primaryHtml: '', | ||
}, | ||
python: { | ||
version: '3.11.5', | ||
packageManager: { | ||
name: 'pip', | ||
packageFile: 'requirements.txt' | ||
} | ||
}, | ||
packages: {}, | ||
files: { | ||
'.': { checksum: '' }, | ||
'meta.yaml': { checksum: '' }, | ||
'requirements.in': { checksum: '' }, | ||
'requirements.txt': { checksum: '' }, | ||
'simple.py': { checksum: '' } | ||
} | ||
}, | ||
connect: { | ||
connect: { | ||
name: '', | ||
connectionTimeout: null, | ||
readTimeout: null, | ||
initTimeout: null, | ||
idleTimeout: null, | ||
maxProcesses: null, | ||
minProcesses: null, | ||
maxConnsPerProcess: null, | ||
loadFactor: null, | ||
runAsCurrentUser: null, | ||
memoryRequest: null, | ||
memoryLimit: null, | ||
cpuRequest: null, | ||
cpuLimit: null | ||
}, | ||
environment: [ | ||
{ | ||
name: '', | ||
value: '', | ||
fromEnvironment: false, | ||
} | ||
] | ||
}, | ||
pythonRequirements: ['YW55aW89PTMuNi4yCmFzZ2lyZWY9PTMuNi4wCmNsaWNrPT04LjEuMwpmYXN0YXBpPT0wLjk1LjIKaDExPT0wLjE0LjAKaWRuYT09My40CnB5ZGFudGljPT0xLjEwLjcKcHlqd3Q9PTIuNy4wCnJzY29ubmVjdC1weXRob249PTEuMTcuMApzZW12ZXI9PTIuMTMuMApzaXg9PTEuMTYuMApzbmlmZmlvPT0xLjMuMApzdGFybGV0dGU9PTAuMjcuMAp0eXBpbmctZXh0ZW5zaW9ucz09NC41LjAKdXZpY29ybj09MC4yMi4wCg=='] | ||
}; | ||
await flushPromises(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was also extremely tricky. Without this our tests execute before the component has the opportunity to re-render after the So we need to mount the component to get the Pinia store, but we need to wait until that is all done before we move on. One way to do this is with The docs for Vue Test Utils also recommend using References: |
||
|
||
expect(api.files.get).toHaveBeenCalledOnce(); | ||
expect(wrapper.text()).toContain('4 files selected from test/sample-content/fastapi-simple (total = 1.0 KB)'); | ||
}); | ||
}); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -26,6 +26,12 @@ | |
"src/*": ["src/*"] | ||
} | ||
}, | ||
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"], | ||
"include": [ | ||
"src/**/*.ts", | ||
"src/**/*.d.ts", | ||
"src/**/*.tsx", | ||
"src/**/*.vue", | ||
"tests/**/*.ts" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Needed to add our test files to ensure they got our TypeScript settings and the path alias. |
||
], | ||
"references": [{ "path": "./tsconfig.node.json" }] | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
/// <reference types="vitest" /> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is needed at the top to expand the config type to include |
||
|
||
import { fileURLToPath } from 'node:url'; | ||
import { defineConfig } from 'vite'; | ||
import vue from '@vitejs/plugin-vue'; | ||
|
@@ -31,5 +33,8 @@ export default defineConfig({ | |
secure: false | ||
} | ||
} | ||
}, | ||
test: { | ||
environment: 'jsdom', | ||
} | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This plugin had to be enabled to avoid an error. I couldn't find a way around this, or what caused it. Perhaps using the
dark
prop uses the Dark plugin behind the scenes. This wasn't documented, but components would not mount using Vue Test Utils without enabling this since$q.dark
's properties were accessed.