Skip to content

Commit

Permalink
feat: more tests setup (#49)
Browse files Browse the repository at this point in the history
* adding achievements store tests and fixing intellisense

* vitest imports finally fully working

* testing is working

* achievements store now fully tested
  • Loading branch information
liana-p committed Apr 11, 2023
1 parent 88069ad commit 984de73
Show file tree
Hide file tree
Showing 16 changed files with 299 additions and 56 deletions.
7 changes: 6 additions & 1 deletion packages/narrat/.vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,10 @@
},
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
},
"typescript.preferences.autoImportFileExcludePatterns": [
"**/node_modules/**",
"**/dist/**",
"**/lib/**"
]
}
7 changes: 7 additions & 0 deletions packages/narrat/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@
"files": [
"dist/"
],
"pnpm": {
"patchedDependencies": {
"@types/[email protected]": "patches-@[email protected]"
}
},
"scripts": {
"test-unit": "vitest",
"coverage": "vitest --coverage",
Expand Down Expand Up @@ -57,6 +62,7 @@
"@sinclair/typebox": "^0.24.28",
"ajv": "^8.11.0",
"ajv-formats": "^2.1.1",
"clone-deep": "^4.0.1",
"deepmerge": "^4.2.2",
"fuse.js": "^6.6.2",
"howler": "^2.2.3",
Expand All @@ -68,6 +74,7 @@
"@pinia/testing": "^0.0.16",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/vue": "^7.0.0",
"@types/clone-deep": "^4.0.1",
"@types/howler": "^2.2.3",
"@types/jest": "^29.5.0",
"@types/js-yaml": "^4.0.5",
Expand Down
12 changes: 12 additions & 0 deletions packages/narrat/patches/patches-@[email protected]
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
diff --git a/index.d.ts b/index.d.ts
index 43ba6b7fe458e77d152fe0b2f7afeac05d8fc563..3bf91587abf21f15ac166bcae1f5a59b23884b87 100755
--- a/index.d.ts
+++ b/index.d.ts
@@ -7,7 +7,7 @@
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// Minimum TypeScript Version: 4.3

-/// <reference types="jest" />
+// See https://github.com/testing-library/jest-dom/issues/427 for reference

import { TestingLibraryMatchers } from './matchers';
19 changes: 13 additions & 6 deletions packages/narrat/src/components/StartMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,22 @@
>
Load Game
</button>
<button v-for="button in extraButtons" :key="button.id" class="button menu-button main-menu-button large override"
:class="`${button.id}-start-menu-button`"
@click="clickExtraButton(button)">
<button
v-for="button in extraButtons"
:key="button.id"
class="button menu-button main-menu-button large override"
:class="`${button.id}-start-menu-button`"
@click="clickExtraButton(button)"
>
{{ button.text }}
</button>
</div>
</div>
<Teleport to="#app-container" v-if="popupComponent">
<ModalWindow @close="closePopupComponent" :class="`start-menu-popup-${popupComponent.id}`">
<ModalWindow
@close="closePopupComponent"
:class="`start-menu-popup-${popupComponent.id}`"
>
<template v-slot:header>
<h3 class="title">
{{ popupComponent.text }}
Expand Down Expand Up @@ -80,7 +87,7 @@ import YesNo from './utils/yes-no.vue';
import { useAudio } from '@/stores/audio-store';
import { inputEvents } from '../utils/InputsListener';
import { useStartMenu } from '@/stores/start-menu-store';
import { CustomStartMenuButton } from '@/lib';
import { CustomStartMenuButton } from '@/exports/plugins';
import ModalWindow from './utils/modal-window.vue';
const hasSave = ref(false);
Expand All @@ -91,7 +98,7 @@ const choosingSave = ref(false);
const startingGame = ref(false);
const listener = ref<null | Function>(null);
const startMenuStore = useStartMenu();
const popupComponent = ref<CustomStartMenuButton | false>(false)
const popupComponent = ref<CustomStartMenuButton | false>(false);
const extraButtons = computed(() => startMenuStore.buttons);
Expand Down
2 changes: 1 addition & 1 deletion packages/narrat/src/components/game-dialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ import { DialogKey, useDialogStore } from '../stores/dialog-store';
import DialogPicture from './dialog-picture.vue';
import DialogBox from '@/dialog-box.vue';
import { useRenderingStore } from '@/stores/rendering-store';
import { useMain } from '@/lib';
import { useMain } from '@/stores/main-store';
import { defaultConfig } from '@/config/config-output';
import { inputEvents } from '../utils/InputsListener';
Expand Down
2 changes: 1 addition & 1 deletion packages/narrat/src/components/inventory/item-details.vue
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
</template>
<script lang="ts" setup>
import { getAssetUrl, getConfig, getItemConfig } from '@/config';
import { useDialogStore } from '@/lib';
import { useDialogStore } from '@/stores/dialog-store';
import { ItemState, useInventory } from '@/stores/inventory-store';
import { computed } from 'vue';
Expand Down
2 changes: 1 addition & 1 deletion packages/narrat/src/components/quests-ui.vue
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
</div>
</template>
<script lang="ts">
import { useRenderingStore } from '@/lib';
import { useRenderingStore } from '@/stores/rendering-store';
import { computed, defineComponent, ref } from 'vue';
import { QuestState, useQuests } from '../stores/quest-log';
import QuestDetails from './quests/QuestDetails.vue';
Expand Down
2 changes: 1 addition & 1 deletion packages/narrat/src/hooks/util-hooks.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import { useRenderingStore } from '@/lib';
import { useRenderingStore } from '@/stores/rendering-store';
import { computed, ref } from 'vue';
import { useMain } from '@/stores/main-store';
163 changes: 163 additions & 0 deletions packages/narrat/src/stores/__tests__/achievements-store.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
import { setActivePinia, createPinia } from 'pinia';
import { describe, it, expect, beforeEach, vi } from 'vitest';
import {
AchievementsSetupConfig,
useAchievements,
} from '../achievements-store';
import { mockConfig } from '@/tests/mock-config';
import cloneDeep from 'clone-deep';
import { useConfig } from '@/stores/config-store';
import { useNotifications } from '../notification-store';

const unlockTime = new Date(2023, 4, 1);

const mockData: AchievementsSetupConfig = {
normalAchievement: {
name: 'Normal Achievement',
description: 'This is a normal achievement',
icon: 'normal',
},
secretAchievement: {
name: 'Secret Achievement',
description: 'This is a secret achievement',
icon: 'secret',
},
};

describe('Achievements Store', () => {
beforeEach(() => {
vi.useFakeTimers();
vi.setSystemTime(unlockTime);
setActivePinia(createPinia());
const config = cloneDeep(mockConfig);
config.achievements.achievements = mockData;
useConfig().setConfig(config);
});

afterEach(() => {
vi.useRealTimers();
});

it('generateSaveData: generates the save data', () => {
const achievements = useAchievements();
achievements.setupAchievements(mockData);
const unlockTime = new Date().toISOString();
achievements.unlock('normalAchievement');
expect(achievements.generateSaveData()).toEqual({
achievements: {
normalAchievement: {
id: 'normalAchievement',
unlocked: true,
unlockTime,
},
secretAchievement: {
id: 'secretAchievement',
unlocked: false,
},
},
});
});

it('loadSaveData: loads the save data', () => {
const achievements = useAchievements();
achievements.setupAchievements(mockData);
achievements.unlock('normalAchievement');
const saveData = achievements.generateSaveData();
achievements.reset(mockData);
achievements.loadSaveData(saveData);
expect(achievements.achievements).toEqual({
normalAchievement: {
id: 'normalAchievement',
unlocked: true,
unlockTime: unlockTime.toISOString(),
},
secretAchievement: {
id: 'secretAchievement',
unlocked: false,
},
});
});

it('setupAchievements: sets up the achievements when passed for configuration', () => {
const achievements = useAchievements();
achievements.setupAchievements(mockData);
expect(achievements.achievements).toEqual({
normalAchievement: {
id: 'normalAchievement',
unlocked: false,
},
secretAchievement: {
id: 'secretAchievement',
unlocked: false,
},
});
});

it('reset: resets the achievements when passed for configuration', () => {
const achievements = useAchievements();
achievements.setupAchievements(mockData);
achievements.unlock('normalAchievement');
achievements.reset(mockData);
expect(achievements.achievements).toEqual({
normalAchievement: {
id: 'normalAchievement',
unlocked: false,
},
secretAchievement: {
id: 'secretAchievement',
unlocked: false,
},
});
});

it('hasAchievement: returns true if the achievement is unlocked', () => {
const achievements = useAchievements();
achievements.setupAchievements(mockData);
achievements.unlock('normalAchievement');
expect(achievements.hasAchievement('normalAchievement')).toBe(true);
});

it('hasAchievement: returns false if the achievement is not unlocked', () => {
const achievements = useAchievements();
achievements.setupAchievements(mockData);
expect(achievements.hasAchievement('normalAchievement')).toBe(false);
});

it('getExistingAchievement: returns the achievement if it exists', () => {
const achievements = useAchievements();
achievements.setupAchievements(mockData);
expect(achievements.getExistingAchievement('normalAchievement')).toEqual({
id: 'normalAchievement',
unlocked: false,
});
});

it('unlock: unlocks the achievement', () => {
const achievements = useAchievements();
achievements.setupAchievements(mockData);
achievements.unlock('normalAchievement');
expect(achievements.hasAchievement('normalAchievement')).toBe(true);
});
it('unlock: sends a notification if the option is enabled', () => {
const achievements = useAchievements();
achievements.setupAchievements(mockData);
const config = useConfig().config;
config.achievements.notifyNewAchievements = true;
useConfig().setConfig(config);
const notifications = useNotifications();
const spy = vi.spyOn(notifications, 'addNotification');
achievements.unlock('normalAchievement');
expect(spy).toHaveBeenCalled();
});
it('unlock: does not send a notification if the option is disabled', () => {
const achievements = useAchievements();
achievements.setupAchievements(mockData);
const config = useConfig().config;
config.achievements.notifyNewAchievements = false;
useConfig().setConfig(config);
const notifications = useNotifications();
const spy = vi.spyOn(notifications, 'addNotification');
achievements.unlock('normalAchievement');
expect(spy).not.toHaveBeenCalled();
});
});
23 changes: 13 additions & 10 deletions packages/narrat/src/stores/start-menu-store.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { CustomStartMenuButton } from '@/lib';
import { CustomStartMenuButton } from '@/exports/plugins';
import { vm } from '@/vm/vm';
import { defineStore } from 'pinia';

export interface StartMenuState {
buttons: CustomStartMenuButton[]
buttons: CustomStartMenuButton[];
}

export const useStartMenu = defineStore('startMenu', {
Expand All @@ -16,15 +16,18 @@ export const useStartMenu = defineStore('startMenu', {
const plugins = vm.plugins;
plugins.forEach((plugin) => {
if (plugin.startMenuButtons) {
plugin.startMenuButtons.forEach(button => {
plugin.startMenuButtons.forEach((button) => {
const app = (window as any).narrat.app;
if (button.popupComponent) {
app.component(button.popupComponent.name, button.popupComponent.component)
app.component(
button.popupComponent.name,
button.popupComponent.component,
);
}
this.buttons.push(button)
})
this.buttons.push(button);
});
}
})
}
}
});
});
},
},
});
9 changes: 9 additions & 0 deletions packages/narrat/src/tests/mock-config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Config, defaultConfig } from '@/config/config-output';
import { defaultLayoutConfig } from '@/config/layout-config';
import { useConfig } from '@/stores/config-store';

export const mockConfig: Config = defaultConfig;

export const setMockConfig = () => {
useConfig().setConfig(mockConfig);
};
2 changes: 1 addition & 1 deletion packages/narrat/src/utils/viewport-utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { buttonsConfig } from '@/config';
import { ButtonConfig } from '@/config/buttons-config';
import { useMain } from '@/lib';
import { useMain } from '@/stores/main-store';
import { ScreenObjectState } from '@/stores/screen-objects-store';

export function isViewportElementClickable(
Expand Down
2 changes: 1 addition & 1 deletion packages/narrat/src/vm/commands/time-commands.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { CommandPlugin } from './command-plugin';
import { useMain } from '@/lib';
import { useMain } from '@/stores/main-store';
export const nowPlugin = CommandPlugin.FromOptions<{}>({
keyword: 'time_now',
argTypes: [],
Expand Down
1 change: 0 additions & 1 deletion packages/narrat/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
"types": ["@testing-library/jest-dom"],
"typeRoots": ["src/types/", "node_modules/@types/"]
},
"exclude": ["**/*.spec.ts"],
"include": [
"src/**/*.ts",
"src/**/*.d.ts",
Expand Down
7 changes: 6 additions & 1 deletion packages/narrat/tsconfig.node.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
{
"compilerOptions": {
"baseUrl": "./",
"composite": true,
"module": "esnext",
"moduleResolution": "node",
"allowSyntheticDefaultImports": true,
"resolveJsonModule": true
"resolveJsonModule": true,
"types": ["jsdom", "vitest/globals", "@testing-library/jest-dom"],
"paths": {
"@/*": ["src/*"]
}
},
"include": ["vite.config.ts", "package.json"]
}
Loading

0 comments on commit 984de73

Please sign in to comment.