Skip to content

Commit

Permalink
add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
keplervital committed Jul 25, 2024
1 parent 3a21048 commit 1f81207
Show file tree
Hide file tree
Showing 8 changed files with 316 additions and 10 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { VueWrapper } from '@vue/test-utils';
import { describe, expect, it } from 'vitest';
import { ChangeCanisterFormValue } from '~/components/change-canister/change-canister.types';
import { mount } from '~/test.utils';
import { ChangeCanisterTargetType } from '~/types/station.types';
import AdvancedUpdateMode from './AdvancedUpdateMode.vue';

describe('AdvancedUpdateMode', () => {
it('renders with empty form', () => {
const wrapper = mount(AdvancedUpdateMode, {
props: {
modelValue: {
wasmInitArg: undefined,
target: undefined,
wasmModule: undefined,
},
},
});

expect(wrapper.exists()).toBe(true);
expect(wrapper.find('[name="target"]').exists()).toBe(true);
expect(wrapper.find('[name="arg"]').exists()).toBe(true);
expect(wrapper.find('[name="wasm"]').exists()).toBe(true);
});

it('when target type changes the modelValue picks up the change', async () => {
const wrapper = mount(AdvancedUpdateMode, {
props: {
modelValue: {
wasmInitArg: undefined,
target: undefined,
wasmModule: undefined,
},
},
}) as unknown as VueWrapper<
InstanceType<typeof AdvancedUpdateMode> & { upgradeTarget: ChangeCanisterTargetType }
>;

// picks up the change to upgrade station
wrapper.vm.upgradeTarget = ChangeCanisterTargetType.UpgradeStation;
await wrapper.vm.$nextTick();
const modelValue = wrapper.emitted('update:modelValue')?.[0]?.[0] as ChangeCanisterFormValue;
expect(modelValue.target).toEqual({ UpgradeStation: null });

// picks up the change to upgrade upgrader
wrapper.vm.upgradeTarget = ChangeCanisterTargetType.UpgradeUpgrader;
await wrapper.vm.$nextTick();
const modelValue2 = wrapper.emitted('update:modelValue')?.[1]?.[0] as ChangeCanisterFormValue;
expect(modelValue2.target).toEqual({ UpgradeUpgrader: null });
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { describe, expect, it } from 'vitest';
import { mount } from '~/test.utils';
import ChangeCanisterConfirmationScreen from './ChangeCanisterConfirmationScreen.vue';

describe('ChangeCanisterConfirmationScreen', () => {
it('confirmation screen has checksum and comment fields', () => {
const wrapper = mount(ChangeCanisterConfirmationScreen, {
props: {
wasmModuleChecksum: 'checksum',
comment: 'My test comment',
},
});

expect(wrapper.exists()).toBe(true);
expect(wrapper.find('[name="wasm_checksum"]').exists()).toBe(true);
expect(wrapper.find('[name="comment"]').exists()).toBe(true);
});

it('confirmation screen shows the checksum in the field in readonly mode', () => {
const wrapper = mount(ChangeCanisterConfirmationScreen, {
props: {
wasmModuleChecksum: 'checksum',
},
});

expect(wrapper.exists()).toBe(true);

const field = wrapper.find('[name="wasm_checksum"]').element as HTMLInputElement;
expect(field.value).toEqual('checksum');
expect(field.readOnly).toBe(true);
});

it('confirmation screen shows the comment in the field in edit mode', () => {
const wrapper = mount(ChangeCanisterConfirmationScreen, {
props: {
wasmModuleChecksum: 'checksum',
comment: 'My test comment',
},
});

expect(wrapper.exists()).toBe(true);

const field = wrapper.find('[name="comment"]').element as HTMLInputElement;
expect(field.value).toEqual('My test comment');
expect(field.readOnly).toBe(false);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

<VTextarea
v-model="comment"
name="arg"
name="comment"
:label="$t(`requests.comment_optional`)"
:prepend-icon="mdiComment"
variant="filled"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import { describe, expect, it, vi } from 'vitest';
import { mockPinia, mount } from '~/test.utils';
import RegistryUpdateMode from './RegistryUpdateMode.vue';
import { useStationStore } from '~/stores/station.store';

describe('RegistryUpdateMode', () => {
it('on mount triggers the check for new updates', () => {
const pinia = mockPinia({ activate: true });
const station = useStationStore();
vi.spyOn(station, 'checkVersionUpdates').mockImplementation(() => Promise.resolve());

const wrapper = mount(
RegistryUpdateMode,
{ props: { modelValue: {} } },
{ plugins: { pinia } },
);

expect(wrapper.exists()).toBe(true);
expect(station.checkVersionUpdates).toHaveBeenCalled();
});

it('shows already in latest version screen', () => {
const pinia = mockPinia({
activate: true,
initialState: {
station: {
versionManagement: {
loading: false,
nextStationVersion: undefined,
nextUpgraderVersion: undefined,
},
},
},
});

const station = useStationStore();
vi.spyOn(station, 'checkVersionUpdates').mockImplementation(() => Promise.resolve());

const wrapper = mount(
RegistryUpdateMode,
{ props: { modelValue: {} } },
{ plugins: { pinia } },
);

expect(wrapper.find('[data-test-id="latest-screen"]').exists()).toBe(true);
});

it('shows update available screen', () => {
const pinia = mockPinia({
activate: true,
initialState: {
station: {
versionManagement: {
loading: false,
nextStationVersion: '1.2.3',
nextUpgraderVersion: '1.2.3',
},
},
},
});

const station = useStationStore();
vi.spyOn(station, 'checkVersionUpdates').mockImplementation(() => Promise.resolve());

const wrapper = mount(
RegistryUpdateMode,
{ props: { modelValue: {} } },
{ plugins: { pinia } },
);

expect(wrapper.find('[data-test-id="update-available-screen"]').exists()).toBe(true);
});

it('shows loading screen while version updates is in progress', () => {
const pinia = mockPinia({
activate: true,
initialState: {
station: {
versionManagement: {
loading: true,
},
},
},
});

const station = useStationStore();
vi.spyOn(station, 'checkVersionUpdates').mockImplementation(() => Promise.resolve());

const wrapper = mount(
RegistryUpdateMode,
{ props: { modelValue: {} } },
{ plugins: { pinia } },
);

expect(station.checkVersionUpdates).not.toHaveBeenCalled();
expect(wrapper.find('[data-test-id="loading-screen"]').exists()).toBe(true);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,18 @@
{{ $t('app.update_recommended_latest') }}
</VAlert>

<p v-if="checkingForUpdates" class="text-h6 py-3">
<p v-if="checkingForUpdates" class="text-h6 py-3" data-test-id="loading-screen">
<VProgressCircular indeterminate color="primary" class="mb-1 mr-2" :size="20" :width="2" />
{{ $t('app.checking_for_updates') }}
</p>

<p v-else-if="!isUpdateAvailable" class="text-h6 py-3">
<p v-else-if="!isUpdateAvailable" class="text-h6 py-3" data-test-id="latest-screen">
{{ $t('app.update_already_latest_version') }}
</p>

<p v-else class="text-h6 py-3">{{ $t('app.update_available') }}</p>
<p v-else class="text-h6 py-3" data-test-id="update-available-screen">
{{ $t('app.update_available') }}
</p>
</template>

<script lang="ts" setup>
Expand Down
33 changes: 33 additions & 0 deletions apps/wallet/src/composables/change-canister.composable.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { describe, expect, it } from 'vitest';
import {
useDefaultUpgradeModel,
useUpgradeTargets,
} from '~/composables/change-canister.composable';
import { setupComponent } from '~/test.utils';
import { ChangeCanisterTargetType } from '~/types/station.types';

describe('change-canister.composable', () => {
it('should return upgrade targets with correct targets', () => {
const vm = setupComponent(() => ({ targets: useUpgradeTargets() }));

expect(vm.targets.station.value).toEqual(ChangeCanisterTargetType.UpgradeStation);
expect(vm.targets.upgrader.value).toEqual(ChangeCanisterTargetType.UpgradeUpgrader);
});

it('should return default form value with empty values', () => {
const { modelValue } = useDefaultUpgradeModel();

expect(modelValue).toEqual({
target: undefined,
wasmModule: undefined,
wasmInitArg: undefined,
comment: undefined,
});
});

it('by default upgrade form should be invalid', () => {
const { valid } = useDefaultUpgradeModel();

expect(valid).toBe(false);
});
});
61 changes: 61 additions & 0 deletions apps/wallet/src/services/control-panel.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { HttpAgent } from '@dfinity/agent';
import { describe, expect, it, vi } from 'vitest';
import { RegistryEntry } from '~/generated/control-panel/control_panel.did';
import { ControlPanelService } from '~/services/control-panel.service';

const mockWasmModuleEntry = (name: string, version: string): RegistryEntry => ({
id: '',
name,
categories: [],
tags: [],
description: 'This is a test description',
created_at: '2024-01-01T00:00:00Z',
updated_at: [],
metadata: [],
value: {
WasmModule: {
dependencies: [],
version,
wasm_artifact_id: '',
},
},
});

describe('ControlPanelService', () => {
it('should find module of a given version', async () => {
const controlPanel = new ControlPanelService(new HttpAgent());
const firstCallEntry = mockWasmModuleEntry('test', '1.0.0');
const secondCallEntry = mockWasmModuleEntry('test', '1.0.1');

vi.spyOn(controlPanel, 'findRegistryEntries')
.mockReturnValue(Promise.resolve({ entries: [], next_offset: [], total: BigInt(0) }))
.mockReturnValueOnce(
Promise.resolve({ entries: [firstCallEntry], next_offset: [BigInt(1)], total: BigInt(2) }),
)
.mockReturnValueOnce(
Promise.resolve({ entries: [secondCallEntry], next_offset: [], total: BigInt(2) }),
);

vi.spyOn(controlPanel, 'getRegistryEntry').mockReturnValue(
Promise.resolve({ entry: secondCallEntry }),
);

const entry = await controlPanel.findModuleVersionRegistryEntry('test', '1.0.1');

expect(controlPanel.findRegistryEntries).toHaveBeenCalledTimes(2);
expect(controlPanel.getRegistryEntry).toHaveBeenCalledTimes(1);
expect(entry).toEqual(mockWasmModuleEntry('test', '1.0.1'));
});

it('should return null if module version is not found', async () => {
const controlPanel = new ControlPanelService(new HttpAgent());

vi.spyOn(controlPanel, 'findRegistryEntries').mockReturnValue(
Promise.resolve({ entries: [], next_offset: [], total: BigInt(0) }),
);

const entry = await controlPanel.findModuleVersionRegistryEntry('test', '1.0.1');

expect(entry).toBeNull();
});
});
26 changes: 20 additions & 6 deletions apps/wallet/src/test.utils.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/* eslint-disable vue/one-component-per-file */
import { createTestingPinia } from '@pinia/testing';
import { mount as componentMount, ComponentMountingOptions } from '@vue/test-utils';
import { StateTree } from 'pinia';
import { Component, ComponentPublicInstance, createApp, defineComponent, Ref } from 'vue';
import { Pinia, setActivePinia, StateTree } from 'pinia';
import { Component, ComponentPublicInstance, createApp, defineComponent, Plugin, Ref } from 'vue';
import { createMemoryHistory, createRouter } from 'vue-router';
import { i18n } from '~/plugins/i18n.plugin';
import { navigation } from '~/plugins/navigation.plugin';
Expand All @@ -21,10 +21,25 @@ export const mockRouter = createRouter({
],
});

export const mockPinia = (opts: { initialState?: StateTree; activate?: boolean }): Pinia => {
const pinia = createTestingPinia({ initialState: opts.initialState });

if (opts.activate) {
setActivePinia(pinia);
}

return pinia;
};

export const mount = <T extends Component>(
component: T,
options: ComponentMountingOptions<T> = {},
{ initialPiniaState }: { initialPiniaState?: StateTree } = {},
overrides: {
initialPiniaState?: StateTree;
plugins?: {
pinia?: Plugin;
};
} = {},
) => {
const mocks = options.global?.mocks || {};
const plugins = options.global?.plugins || [];
Expand All @@ -34,9 +49,8 @@ export const mount = <T extends Component>(
global: {
...options.global,
plugins: [
createTestingPinia({
initialState: initialPiniaState,
}),
overrides.plugins?.pinia ??
createTestingPinia({ initialState: overrides.initialPiniaState }),
vuetify(),
i18n,
serviceManager,
Expand Down

0 comments on commit 1f81207

Please sign in to comment.