mirror of
https://github.com/mulgadc/spinifex.git
synced 2026-10-22 20:26:44 +00:00
feat: enforce frontend code coverage
This commit is contained in:
@@ -42,8 +42,8 @@ jobs:
|
||||
- name: Run Biome Check
|
||||
run: pnpm check
|
||||
|
||||
- name: Run Tests
|
||||
run: pnpm test
|
||||
- name: Run Tests with Coverage
|
||||
run: pnpm test:coverage
|
||||
|
||||
- name: Build Frontend
|
||||
run: pnpm build
|
||||
|
||||
@@ -2,3 +2,4 @@ node_modules
|
||||
.tanstack
|
||||
*.tsbuildinfo
|
||||
.pnpm-store
|
||||
coverage
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
@@ -9,6 +9,7 @@
|
||||
"check": "biome check",
|
||||
"fix": "biome check --fix",
|
||||
"test": "vitest run",
|
||||
"test:coverage": "vitest run --coverage",
|
||||
"test:watch": "vitest"
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -45,6 +46,7 @@
|
||||
"@typescript/native-preview": "7.0.0-dev.20260307.1",
|
||||
"@vitejs/plugin-basic-ssl": "^2.1.4",
|
||||
"@vitejs/plugin-react": "^5.1.4",
|
||||
"@vitest/coverage-v8": "^4.0.18",
|
||||
"babel-plugin-react-compiler": "^1.0.0",
|
||||
"jsdom": "^28.1.0",
|
||||
"typescript": "^5.9.3",
|
||||
|
||||
+114
@@ -102,6 +102,9 @@ importers:
|
||||
'@vitejs/plugin-react':
|
||||
specifier: ^5.1.4
|
||||
version: 5.1.4(vite@7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0))
|
||||
'@vitest/coverage-v8':
|
||||
specifier: ^4.0.18
|
||||
version: 4.0.18(vitest@4.0.18(@types/node@24.12.0)(jiti@2.6.1)(jsdom@28.1.0)(lightningcss@1.31.1)(tsx@4.21.0))
|
||||
babel-plugin-react-compiler:
|
||||
specifier: ^1.0.0
|
||||
version: 1.0.0
|
||||
@@ -440,6 +443,10 @@ packages:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@bcoe/v8-coverage@1.0.2':
|
||||
resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
'@biomejs/biome@2.4.6':
|
||||
resolution: {integrity: sha512-QnHe81PMslpy3mnpL8DnO2M4S4ZnYPkjlGCLWBZT/3R9M6b5daArWMMtEfP52/n174RKnwRIf3oT8+wc9ihSfQ==}
|
||||
engines: {node: '>=14.21.3'}
|
||||
@@ -1382,6 +1389,15 @@ packages:
|
||||
peerDependencies:
|
||||
vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0
|
||||
|
||||
'@vitest/coverage-v8@4.0.18':
|
||||
resolution: {integrity: sha512-7i+N2i0+ME+2JFZhfuz7Tg/FqKtilHjGyGvoHYQ6iLV0zahbsJ9sljC9OcFcPDbhYKCet+sG8SsVqlyGvPflZg==}
|
||||
peerDependencies:
|
||||
'@vitest/browser': 4.0.18
|
||||
vitest: 4.0.18
|
||||
peerDependenciesMeta:
|
||||
'@vitest/browser':
|
||||
optional: true
|
||||
|
||||
'@vitest/expect@4.0.18':
|
||||
resolution: {integrity: sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==}
|
||||
|
||||
@@ -1451,6 +1467,9 @@ packages:
|
||||
resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==}
|
||||
engines: {node: '>=4'}
|
||||
|
||||
ast-v8-to-istanbul@0.3.12:
|
||||
resolution: {integrity: sha512-BRRC8VRZY2R4Z4lFIL35MwNXmwVqBityvOIwETtsCSwvjl0IdgFsy9NhdaA6j74nUdtJJlIypeRhpDam19Wq3g==}
|
||||
|
||||
babel-dead-code-elimination@1.0.12:
|
||||
resolution: {integrity: sha512-GERT7L2TiYcYDtYk1IpD+ASAYXjKbLTDPhBtYj7X1NuRMDTMtAx9kyBenub1Ev41lo91OHCKdmP+egTDmfQ7Ig==}
|
||||
|
||||
@@ -1660,10 +1679,17 @@ packages:
|
||||
graceful-fs@4.2.11:
|
||||
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
|
||||
|
||||
has-flag@4.0.0:
|
||||
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
html-encoding-sniffer@6.0.0:
|
||||
resolution: {integrity: sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==}
|
||||
engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
|
||||
|
||||
html-escaper@2.0.2:
|
||||
resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==}
|
||||
|
||||
http-proxy-agent@7.0.2:
|
||||
resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==}
|
||||
engines: {node: '>= 14'}
|
||||
@@ -1705,10 +1731,25 @@ packages:
|
||||
resolution: {integrity: sha512-waFfC72ZNfwLLuJ2iLaoVaqcNo+CAaLR7xCpAn0Y5WfGzkNHv7ZN39Vbi1y+kb+Zs46XHOX3tZNExroFUPX+Kg==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
istanbul-lib-coverage@3.2.2:
|
||||
resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
istanbul-lib-report@3.0.1:
|
||||
resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
istanbul-reports@3.2.0:
|
||||
resolution: {integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
jiti@2.6.1:
|
||||
resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==}
|
||||
hasBin: true
|
||||
|
||||
js-tokens@10.0.0:
|
||||
resolution: {integrity: sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==}
|
||||
|
||||
js-tokens@4.0.0:
|
||||
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
|
||||
|
||||
@@ -1827,6 +1868,13 @@ packages:
|
||||
magic-string@0.30.21:
|
||||
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
|
||||
|
||||
magicast@0.5.2:
|
||||
resolution: {integrity: sha512-E3ZJh4J3S9KfwdjZhe2afj6R9lGIN5Pher1pF39UGrXRqq/VDaGVIGN13BjHd2u8B61hArAGOnso7nBOouW3TQ==}
|
||||
|
||||
make-dir@4.0.0:
|
||||
resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
mdn-data@2.27.1:
|
||||
resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==}
|
||||
|
||||
@@ -1970,6 +2018,11 @@ packages:
|
||||
resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
|
||||
hasBin: true
|
||||
|
||||
semver@7.7.4:
|
||||
resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==}
|
||||
engines: {node: '>=10'}
|
||||
hasBin: true
|
||||
|
||||
seroval-plugins@1.5.0:
|
||||
resolution: {integrity: sha512-EAHqADIQondwRZIdeW2I636zgsODzoBDwb3PT/+7TLDWyw1Dy/Xv7iGUIEXXav7usHDE9HVhOU61irI3EnyyHA==}
|
||||
engines: {node: '>=10'}
|
||||
@@ -2017,6 +2070,10 @@ packages:
|
||||
strnum@2.2.0:
|
||||
resolution: {integrity: sha512-Y7Bj8XyJxnPAORMZj/xltsfo55uOiyHcU2tnAVzHUnSJR/KsEX+9RoDeXEnsXtl/CX4fAcrt64gZ13aGaWPeBg==}
|
||||
|
||||
supports-color@7.2.0:
|
||||
resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
symbol-tree@3.2.4:
|
||||
resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==}
|
||||
|
||||
@@ -2969,6 +3026,8 @@ snapshots:
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.14
|
||||
|
||||
'@bcoe/v8-coverage@1.0.2': {}
|
||||
|
||||
'@biomejs/biome@2.4.6':
|
||||
optionalDependencies:
|
||||
'@biomejs/cli-darwin-arm64': 2.4.6
|
||||
@@ -3865,6 +3924,20 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@vitest/coverage-v8@4.0.18(vitest@4.0.18(@types/node@24.12.0)(jiti@2.6.1)(jsdom@28.1.0)(lightningcss@1.31.1)(tsx@4.21.0))':
|
||||
dependencies:
|
||||
'@bcoe/v8-coverage': 1.0.2
|
||||
'@vitest/utils': 4.0.18
|
||||
ast-v8-to-istanbul: 0.3.12
|
||||
istanbul-lib-coverage: 3.2.2
|
||||
istanbul-lib-report: 3.0.1
|
||||
istanbul-reports: 3.2.0
|
||||
magicast: 0.5.2
|
||||
obug: 2.1.1
|
||||
std-env: 3.10.0
|
||||
tinyrainbow: 3.0.3
|
||||
vitest: 4.0.18(@types/node@24.12.0)(jiti@2.6.1)(jsdom@28.1.0)(lightningcss@1.31.1)(tsx@4.21.0)
|
||||
|
||||
'@vitest/expect@4.0.18':
|
||||
dependencies:
|
||||
'@standard-schema/spec': 1.1.0
|
||||
@@ -3931,6 +4004,12 @@ snapshots:
|
||||
dependencies:
|
||||
tslib: 2.8.1
|
||||
|
||||
ast-v8-to-istanbul@0.3.12:
|
||||
dependencies:
|
||||
'@jridgewell/trace-mapping': 0.3.31
|
||||
estree-walker: 3.0.3
|
||||
js-tokens: 10.0.0
|
||||
|
||||
babel-dead-code-elimination@1.0.12:
|
||||
dependencies:
|
||||
'@babel/core': 7.29.0
|
||||
@@ -4138,12 +4217,16 @@ snapshots:
|
||||
|
||||
graceful-fs@4.2.11: {}
|
||||
|
||||
has-flag@4.0.0: {}
|
||||
|
||||
html-encoding-sniffer@6.0.0:
|
||||
dependencies:
|
||||
'@exodus/bytes': 1.15.0
|
||||
transitivePeerDependencies:
|
||||
- '@noble/hashes'
|
||||
|
||||
html-escaper@2.0.2: {}
|
||||
|
||||
http-proxy-agent@7.0.2:
|
||||
dependencies:
|
||||
agent-base: 7.1.4
|
||||
@@ -4180,8 +4263,23 @@ snapshots:
|
||||
|
||||
isbot@5.1.35: {}
|
||||
|
||||
istanbul-lib-coverage@3.2.2: {}
|
||||
|
||||
istanbul-lib-report@3.0.1:
|
||||
dependencies:
|
||||
istanbul-lib-coverage: 3.2.2
|
||||
make-dir: 4.0.0
|
||||
supports-color: 7.2.0
|
||||
|
||||
istanbul-reports@3.2.0:
|
||||
dependencies:
|
||||
html-escaper: 2.0.2
|
||||
istanbul-lib-report: 3.0.1
|
||||
|
||||
jiti@2.6.1: {}
|
||||
|
||||
js-tokens@10.0.0: {}
|
||||
|
||||
js-tokens@4.0.0: {}
|
||||
|
||||
jsdom@28.1.0:
|
||||
@@ -4282,6 +4380,16 @@ snapshots:
|
||||
dependencies:
|
||||
'@jridgewell/sourcemap-codec': 1.5.5
|
||||
|
||||
magicast@0.5.2:
|
||||
dependencies:
|
||||
'@babel/parser': 7.29.0
|
||||
'@babel/types': 7.29.0
|
||||
source-map-js: 1.2.1
|
||||
|
||||
make-dir@4.0.0:
|
||||
dependencies:
|
||||
semver: 7.7.4
|
||||
|
||||
mdn-data@2.27.1: {}
|
||||
|
||||
min-indent@1.0.1: {}
|
||||
@@ -4426,6 +4534,8 @@ snapshots:
|
||||
|
||||
semver@6.3.1: {}
|
||||
|
||||
semver@7.7.4: {}
|
||||
|
||||
seroval-plugins@1.5.0(seroval@1.5.0):
|
||||
dependencies:
|
||||
seroval: 1.5.0
|
||||
@@ -4461,6 +4571,10 @@ snapshots:
|
||||
|
||||
strnum@2.2.0: {}
|
||||
|
||||
supports-color@7.2.0:
|
||||
dependencies:
|
||||
has-flag: 4.0.0
|
||||
|
||||
symbol-tree@3.2.4: {}
|
||||
|
||||
tabbable@6.4.0: {}
|
||||
|
||||
@@ -10,9 +10,26 @@ vi.mock("@/lib/awsClient", () => ({
|
||||
}))
|
||||
|
||||
import {
|
||||
useAttachVolume,
|
||||
useCopySnapshot,
|
||||
useCreateImage,
|
||||
useCreateInstance,
|
||||
useCreateKeyPair,
|
||||
useCreateSnapshot,
|
||||
useCreateSubnet,
|
||||
useCreateVolume,
|
||||
useCreateVpc,
|
||||
useDeleteKeyPair,
|
||||
useDeleteSnapshot,
|
||||
useDeleteSubnet,
|
||||
useDeleteVolume,
|
||||
useDeleteVpc,
|
||||
useDetachVolume,
|
||||
useGetConsoleOutput,
|
||||
useImportKeyPair,
|
||||
useModifyInstanceAttribute,
|
||||
useModifyVolume,
|
||||
useRebootInstance,
|
||||
useStartInstance,
|
||||
useStopInstance,
|
||||
useTerminateInstance,
|
||||
@@ -187,6 +204,247 @@ describe("useImportKeyPair", () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe("useRebootInstance", () => {
|
||||
it("sends RebootInstancesCommand with the instance ID", async () => {
|
||||
createQueryClient()
|
||||
const { result } = renderHook(() => useRebootInstance(), { wrapper })
|
||||
|
||||
result.current.mutate("i-abc123")
|
||||
|
||||
await waitFor(() => expect(result.current.isSuccess).toBe(true))
|
||||
expect(mockSend.mock.calls[0]?.[0].input).toEqual({
|
||||
InstanceIds: ["i-abc123"],
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("useCreateKeyPair", () => {
|
||||
it("sends CreateKeyPairCommand with key name and rsa type", async () => {
|
||||
createQueryClient()
|
||||
const { result } = renderHook(() => useCreateKeyPair(), { wrapper })
|
||||
|
||||
result.current.mutate({ keyName: "my-key" })
|
||||
|
||||
await waitFor(() => expect(result.current.isSuccess).toBe(true))
|
||||
expect(mockSend.mock.calls[0]?.[0].input).toEqual({
|
||||
KeyName: "my-key",
|
||||
KeyType: "rsa",
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("useDeleteKeyPair", () => {
|
||||
it("sends DeleteKeyPairCommand with key pair ID", async () => {
|
||||
createQueryClient()
|
||||
const { result } = renderHook(() => useDeleteKeyPair(), { wrapper })
|
||||
|
||||
result.current.mutate("kp-abc123")
|
||||
|
||||
await waitFor(() => expect(result.current.isSuccess).toBe(true))
|
||||
expect(mockSend.mock.calls[0]?.[0].input).toEqual({
|
||||
KeyPairId: "kp-abc123",
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("useCreateVolume", () => {
|
||||
it("sends CreateVolumeCommand with size and availability zone", async () => {
|
||||
createQueryClient()
|
||||
const { result } = renderHook(() => useCreateVolume(), { wrapper })
|
||||
|
||||
result.current.mutate({ size: 100, availabilityZone: "us-east-1a" })
|
||||
|
||||
await waitFor(() => expect(result.current.isSuccess).toBe(true))
|
||||
expect(mockSend.mock.calls[0]?.[0].input).toEqual({
|
||||
Size: 100,
|
||||
AvailabilityZone: "us-east-1a",
|
||||
VolumeType: "gp3",
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("useModifyVolume", () => {
|
||||
it("sends ModifyVolumeCommand with volume ID and new size", async () => {
|
||||
createQueryClient()
|
||||
const { result } = renderHook(() => useModifyVolume(), { wrapper })
|
||||
|
||||
result.current.mutate({ volumeId: "vol-123", size: 200 })
|
||||
|
||||
await waitFor(() => expect(result.current.isSuccess).toBe(true))
|
||||
expect(mockSend.mock.calls[0]?.[0].input).toEqual({
|
||||
VolumeId: "vol-123",
|
||||
Size: 200,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("useDeleteVolume", () => {
|
||||
it("sends DeleteVolumeCommand with volume ID", async () => {
|
||||
createQueryClient()
|
||||
const { result } = renderHook(() => useDeleteVolume(), { wrapper })
|
||||
|
||||
result.current.mutate("vol-123")
|
||||
|
||||
await waitFor(() => expect(result.current.isSuccess).toBe(true))
|
||||
expect(mockSend.mock.calls[0]?.[0].input).toEqual({
|
||||
VolumeId: "vol-123",
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("useCreateSnapshot", () => {
|
||||
it("sends CreateSnapshotCommand with volume ID and description", async () => {
|
||||
createQueryClient()
|
||||
const { result } = renderHook(() => useCreateSnapshot(), { wrapper })
|
||||
|
||||
result.current.mutate({ volumeId: "vol-123", description: "backup" })
|
||||
|
||||
await waitFor(() => expect(result.current.isSuccess).toBe(true))
|
||||
expect(mockSend.mock.calls[0]?.[0].input).toEqual({
|
||||
VolumeId: "vol-123",
|
||||
Description: "backup",
|
||||
})
|
||||
})
|
||||
|
||||
it("omits Description when empty", async () => {
|
||||
createQueryClient()
|
||||
const { result } = renderHook(() => useCreateSnapshot(), { wrapper })
|
||||
|
||||
result.current.mutate({ volumeId: "vol-123", description: "" })
|
||||
|
||||
await waitFor(() => expect(result.current.isSuccess).toBe(true))
|
||||
expect(mockSend.mock.calls[0]?.[0].input.Description).toBeUndefined()
|
||||
})
|
||||
})
|
||||
|
||||
describe("useDeleteSnapshot", () => {
|
||||
it("sends DeleteSnapshotCommand with snapshot ID", async () => {
|
||||
createQueryClient()
|
||||
const { result } = renderHook(() => useDeleteSnapshot(), { wrapper })
|
||||
|
||||
result.current.mutate("snap-123")
|
||||
|
||||
await waitFor(() => expect(result.current.isSuccess).toBe(true))
|
||||
expect(mockSend.mock.calls[0]?.[0].input).toEqual({
|
||||
SnapshotId: "snap-123",
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("useCopySnapshot", () => {
|
||||
it("sends CopySnapshotCommand with source details", async () => {
|
||||
createQueryClient()
|
||||
const { result } = renderHook(() => useCopySnapshot(), { wrapper })
|
||||
|
||||
result.current.mutate({
|
||||
sourceSnapshotId: "snap-123",
|
||||
sourceRegion: "us-east-1",
|
||||
description: "copy",
|
||||
})
|
||||
|
||||
await waitFor(() => expect(result.current.isSuccess).toBe(true))
|
||||
expect(mockSend.mock.calls[0]?.[0].input).toEqual({
|
||||
SourceSnapshotId: "snap-123",
|
||||
SourceRegion: "us-east-1",
|
||||
Description: "copy",
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("useAttachVolume", () => {
|
||||
it("sends AttachVolumeCommand with volume, instance, and device", async () => {
|
||||
createQueryClient()
|
||||
const { result } = renderHook(() => useAttachVolume(), { wrapper })
|
||||
|
||||
result.current.mutate({
|
||||
volumeId: "vol-123",
|
||||
instanceId: "i-abc",
|
||||
device: "/dev/sdf",
|
||||
})
|
||||
|
||||
await waitFor(() => expect(result.current.isSuccess).toBe(true))
|
||||
expect(mockSend.mock.calls[0]?.[0].input).toEqual({
|
||||
VolumeId: "vol-123",
|
||||
InstanceId: "i-abc",
|
||||
Device: "/dev/sdf",
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("useDetachVolume", () => {
|
||||
it("sends DetachVolumeCommand with volume, instance, and force", async () => {
|
||||
createQueryClient()
|
||||
const { result } = renderHook(() => useDetachVolume(), { wrapper })
|
||||
|
||||
result.current.mutate({
|
||||
volumeId: "vol-123",
|
||||
instanceId: "i-abc",
|
||||
force: true,
|
||||
})
|
||||
|
||||
await waitFor(() => expect(result.current.isSuccess).toBe(true))
|
||||
expect(mockSend.mock.calls[0]?.[0].input).toEqual({
|
||||
VolumeId: "vol-123",
|
||||
InstanceId: "i-abc",
|
||||
Force: true,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("useModifyInstanceAttribute", () => {
|
||||
it("sends ModifyInstanceAttributeCommand with instance type", async () => {
|
||||
createQueryClient()
|
||||
const { result } = renderHook(() => useModifyInstanceAttribute(), {
|
||||
wrapper,
|
||||
})
|
||||
|
||||
result.current.mutate({
|
||||
instanceId: "i-abc",
|
||||
instanceType: "t3.large",
|
||||
})
|
||||
|
||||
await waitFor(() => expect(result.current.isSuccess).toBe(true))
|
||||
expect(mockSend.mock.calls[0]?.[0].input).toEqual({
|
||||
InstanceId: "i-abc",
|
||||
InstanceType: { Value: "t3.large" },
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("useGetConsoleOutput", () => {
|
||||
it("sends GetConsoleOutputCommand with instance ID", async () => {
|
||||
createQueryClient()
|
||||
const { result } = renderHook(() => useGetConsoleOutput(), { wrapper })
|
||||
|
||||
result.current.mutate("i-abc123")
|
||||
|
||||
await waitFor(() => expect(result.current.isSuccess).toBe(true))
|
||||
expect(mockSend.mock.calls[0]?.[0].input).toEqual({
|
||||
InstanceId: "i-abc123",
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("useCreateImage", () => {
|
||||
it("sends CreateImageCommand with instance ID and name", async () => {
|
||||
createQueryClient()
|
||||
const { result } = renderHook(() => useCreateImage(), { wrapper })
|
||||
|
||||
result.current.mutate({
|
||||
instanceId: "i-abc",
|
||||
name: "my-image",
|
||||
description: "test image",
|
||||
})
|
||||
|
||||
await waitFor(() => expect(result.current.isSuccess).toBe(true))
|
||||
expect(mockSend.mock.calls[0]?.[0].input).toEqual({
|
||||
InstanceId: "i-abc",
|
||||
Name: "my-image",
|
||||
Description: "test image",
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("useCreateVpc", () => {
|
||||
it("includes TagSpecifications when name is provided", async () => {
|
||||
createQueryClient()
|
||||
@@ -216,3 +474,51 @@ describe("useCreateVpc", () => {
|
||||
expect(mockSend.mock.calls[0]?.[0].input.TagSpecifications).toBeUndefined()
|
||||
})
|
||||
})
|
||||
|
||||
describe("useDeleteVpc", () => {
|
||||
it("sends DeleteVpcCommand with VPC ID", async () => {
|
||||
createQueryClient()
|
||||
const { result } = renderHook(() => useDeleteVpc(), { wrapper })
|
||||
|
||||
result.current.mutate("vpc-123")
|
||||
|
||||
await waitFor(() => expect(result.current.isSuccess).toBe(true))
|
||||
expect(mockSend.mock.calls[0]?.[0].input).toEqual({
|
||||
VpcId: "vpc-123",
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("useCreateSubnet", () => {
|
||||
it("sends CreateSubnetCommand with VPC ID and CIDR block", async () => {
|
||||
createQueryClient()
|
||||
const { result } = renderHook(() => useCreateSubnet(), { wrapper })
|
||||
|
||||
result.current.mutate({
|
||||
vpcId: "vpc-123",
|
||||
cidrBlock: "10.0.1.0/24",
|
||||
availabilityZone: "us-east-1a",
|
||||
})
|
||||
|
||||
await waitFor(() => expect(result.current.isSuccess).toBe(true))
|
||||
expect(mockSend.mock.calls[0]?.[0].input).toEqual({
|
||||
VpcId: "vpc-123",
|
||||
CidrBlock: "10.0.1.0/24",
|
||||
AvailabilityZone: "us-east-1a",
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("useDeleteSubnet", () => {
|
||||
it("sends DeleteSubnetCommand with subnet ID", async () => {
|
||||
createQueryClient()
|
||||
const { result } = renderHook(() => useDeleteSubnet(), { wrapper })
|
||||
|
||||
result.current.mutate("subnet-123")
|
||||
|
||||
await waitFor(() => expect(result.current.isSuccess).toBe(true))
|
||||
expect(mockSend.mock.calls[0]?.[0].input).toEqual({
|
||||
SubnetId: "subnet-123",
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { describe, expect, it, vi } from "vitest"
|
||||
import { afterEach, describe, expect, it, vi } from "vitest"
|
||||
|
||||
const mockSend = vi.fn().mockResolvedValue({})
|
||||
|
||||
@@ -147,6 +147,10 @@ describe("staleTime and refetchInterval", () => {
|
||||
})
|
||||
|
||||
describe("queryFn", () => {
|
||||
afterEach(() => {
|
||||
mockSend.mockClear()
|
||||
})
|
||||
|
||||
it("ec2ImageQueryOptions returns empty result for undefined imageId", async () => {
|
||||
const options = ec2ImageQueryOptions(undefined)
|
||||
const queryFn = options.queryFn as (ctx: never) => Promise<unknown>
|
||||
@@ -154,4 +158,159 @@ describe("queryFn", () => {
|
||||
expect(result).toEqual({ Images: [], $metadata: {} })
|
||||
expect(mockSend).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it("ec2ImageQueryOptions sends DescribeImagesCommand for valid imageId", async () => {
|
||||
const queryFn = ec2ImageQueryOptions("ami-123").queryFn as (
|
||||
ctx: never,
|
||||
) => Promise<unknown>
|
||||
await queryFn({} as never)
|
||||
expect(mockSend).toHaveBeenCalledOnce()
|
||||
expect(mockSend.mock.calls[0]?.[0].input).toEqual({
|
||||
ImageIds: ["ami-123"],
|
||||
})
|
||||
})
|
||||
|
||||
it("ec2InstancesQueryOptions sends DescribeInstancesCommand", async () => {
|
||||
const queryFn = ec2InstancesQueryOptions.queryFn as (
|
||||
ctx: never,
|
||||
) => Promise<unknown>
|
||||
await queryFn({} as never)
|
||||
expect(mockSend).toHaveBeenCalledOnce()
|
||||
expect(mockSend.mock.calls[0]?.[0].input).toEqual({})
|
||||
})
|
||||
|
||||
it("ec2InstanceQueryOptions sends DescribeInstancesCommand with ID", async () => {
|
||||
const queryFn = ec2InstanceQueryOptions("i-123").queryFn as (
|
||||
ctx: never,
|
||||
) => Promise<unknown>
|
||||
await queryFn({} as never)
|
||||
expect(mockSend.mock.calls[0]?.[0].input).toEqual({
|
||||
InstanceIds: ["i-123"],
|
||||
})
|
||||
})
|
||||
|
||||
it("ec2KeyPairsQueryOptions sends DescribeKeyPairsCommand", async () => {
|
||||
const queryFn = ec2KeyPairsQueryOptions.queryFn as (
|
||||
ctx: never,
|
||||
) => Promise<unknown>
|
||||
await queryFn({} as never)
|
||||
expect(mockSend).toHaveBeenCalledOnce()
|
||||
expect(mockSend.mock.calls[0]?.[0].input).toEqual({})
|
||||
})
|
||||
|
||||
it("ec2KeyPairQueryOptions sends DescribeKeyPairsCommand with ID", async () => {
|
||||
const queryFn = ec2KeyPairQueryOptions("kp-abc").queryFn as (
|
||||
ctx: never,
|
||||
) => Promise<unknown>
|
||||
await queryFn({} as never)
|
||||
expect(mockSend.mock.calls[0]?.[0].input).toEqual({
|
||||
KeyPairIds: ["kp-abc"],
|
||||
})
|
||||
})
|
||||
|
||||
it("ec2VolumesQueryOptions sends DescribeVolumesCommand", async () => {
|
||||
const queryFn = ec2VolumesQueryOptions.queryFn as (
|
||||
ctx: never,
|
||||
) => Promise<unknown>
|
||||
await queryFn({} as never)
|
||||
expect(mockSend).toHaveBeenCalledOnce()
|
||||
})
|
||||
|
||||
it("ec2VolumeQueryOptions sends DescribeVolumesCommand with ID", async () => {
|
||||
const queryFn = ec2VolumeQueryOptions("vol-1").queryFn as (
|
||||
ctx: never,
|
||||
) => Promise<unknown>
|
||||
await queryFn({} as never)
|
||||
expect(mockSend.mock.calls[0]?.[0].input).toEqual({
|
||||
VolumeIds: ["vol-1"],
|
||||
})
|
||||
})
|
||||
|
||||
it("ec2SnapshotsQueryOptions sends DescribeSnapshotsCommand", async () => {
|
||||
const queryFn = ec2SnapshotsQueryOptions.queryFn as (
|
||||
ctx: never,
|
||||
) => Promise<unknown>
|
||||
await queryFn({} as never)
|
||||
expect(mockSend).toHaveBeenCalledOnce()
|
||||
})
|
||||
|
||||
it("ec2SnapshotQueryOptions sends DescribeSnapshotsCommand with ID", async () => {
|
||||
const queryFn = ec2SnapshotQueryOptions("snap-1").queryFn as (
|
||||
ctx: never,
|
||||
) => Promise<unknown>
|
||||
await queryFn({} as never)
|
||||
expect(mockSend.mock.calls[0]?.[0].input).toEqual({
|
||||
SnapshotIds: ["snap-1"],
|
||||
})
|
||||
})
|
||||
|
||||
it("ec2VpcsQueryOptions sends DescribeVpcsCommand", async () => {
|
||||
const queryFn = ec2VpcsQueryOptions.queryFn as (
|
||||
ctx: never,
|
||||
) => Promise<unknown>
|
||||
await queryFn({} as never)
|
||||
expect(mockSend).toHaveBeenCalledOnce()
|
||||
})
|
||||
|
||||
it("ec2VpcQueryOptions sends DescribeVpcsCommand with ID", async () => {
|
||||
const queryFn = ec2VpcQueryOptions("vpc-1").queryFn as (
|
||||
ctx: never,
|
||||
) => Promise<unknown>
|
||||
await queryFn({} as never)
|
||||
expect(mockSend.mock.calls[0]?.[0].input).toEqual({
|
||||
VpcIds: ["vpc-1"],
|
||||
})
|
||||
})
|
||||
|
||||
it("ec2SubnetsQueryOptions sends DescribeSubnetsCommand", async () => {
|
||||
const queryFn = ec2SubnetsQueryOptions.queryFn as (
|
||||
ctx: never,
|
||||
) => Promise<unknown>
|
||||
await queryFn({} as never)
|
||||
expect(mockSend).toHaveBeenCalledOnce()
|
||||
})
|
||||
|
||||
it("ec2SubnetQueryOptions sends DescribeSubnetsCommand with ID", async () => {
|
||||
const queryFn = ec2SubnetQueryOptions("subnet-1").queryFn as (
|
||||
ctx: never,
|
||||
) => Promise<unknown>
|
||||
await queryFn({} as never)
|
||||
expect(mockSend.mock.calls[0]?.[0].input).toEqual({
|
||||
SubnetIds: ["subnet-1"],
|
||||
})
|
||||
})
|
||||
|
||||
it("ec2AvailabilityZonesQueryOptions sends DescribeAvailabilityZonesCommand", async () => {
|
||||
const queryFn = ec2AvailabilityZonesQueryOptions.queryFn as (
|
||||
ctx: never,
|
||||
) => Promise<unknown>
|
||||
await queryFn({} as never)
|
||||
expect(mockSend).toHaveBeenCalledOnce()
|
||||
})
|
||||
|
||||
it("ec2RegionsQueryOptions sends DescribeRegionsCommand", async () => {
|
||||
const queryFn = ec2RegionsQueryOptions.queryFn as (
|
||||
ctx: never,
|
||||
) => Promise<unknown>
|
||||
await queryFn({} as never)
|
||||
expect(mockSend).toHaveBeenCalledOnce()
|
||||
})
|
||||
|
||||
it("ec2ImagesQueryOptions sends DescribeImagesCommand", async () => {
|
||||
const queryFn = ec2ImagesQueryOptions.queryFn as (
|
||||
ctx: never,
|
||||
) => Promise<unknown>
|
||||
await queryFn({} as never)
|
||||
expect(mockSend).toHaveBeenCalledOnce()
|
||||
})
|
||||
|
||||
it("ec2InstanceTypesQueryOptions sends DescribeInstanceTypesCommand with filter", async () => {
|
||||
const queryFn = ec2InstanceTypesQueryOptions.queryFn as (
|
||||
ctx: never,
|
||||
) => Promise<unknown>
|
||||
await queryFn({} as never)
|
||||
expect(mockSend.mock.calls[0]?.[0].input).toEqual({
|
||||
Filters: [{ Name: "capacity", Values: ["true"] }],
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -47,5 +47,10 @@ export default defineConfig({
|
||||
globals: true,
|
||||
environment: "jsdom",
|
||||
setupFiles: "./src/test/setup.ts",
|
||||
coverage: {
|
||||
thresholds: {
|
||||
statements: 70,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user