Some more tests

This commit is contained in:
James Lyne 2022-06-23 15:01:34 +01:00
parent fb53bc2c2a
commit e143471fa8
6 changed files with 471 additions and 6 deletions

View File

@ -17,21 +17,21 @@
<template>
<section class="sidebar" role="none" ref="sidebar">
<header class="sidebar__buttons">
<button v-if="mapCount > 1 || serverCount > 1" class="button--maps" data-section="maps"
<button ref="maps-button" v-if="mapCount > 1 || serverCount > 1" class="button--maps" data-section="maps"
:title="mapCount > 1 ? messageWorlds : messageServers"
:aria-label="mapCount > 1 ? messageWorlds : messageServers"
:aria-expanded="mapsVisible"
@click="handleSectionClick" @keydown="handleSectionKeydown">
<SvgIcon :name="mapCount > 1 ? 'maps' : 'servers'"></SvgIcon>
<SvgIcon ref="maps-icon" :name="mapCount > 1 ? 'maps' : 'servers'"></SvgIcon>
</button>
<button v-if="markerUIEnabled" class="button--markers" data-section="markers"
<button ref="markers-button" v-if="markerUIEnabled" class="button--markers" data-section="markers"
:title="messageMarkers"
:aria-label="messageMarkers"
:aria-expanded="markersVisible"
@click="handleSectionClick" @keydown="handleSectionKeydown">
<SvgIcon name="marker_point"></SvgIcon>
</button>
<button v-if="playerMakersEnabled" class="button--players" data-section="players"
<button ref="players-button" v-if="playerMakersEnabled" class="button--players" data-section="players"
:title="messagePlayers" :aria-label="messagePlayers" :aria-expanded="playersVisible"
@click="handleSectionClick" @keydown="handleSectionKeydown">
<SvgIcon name="players"></SvgIcon>

View File

@ -0,0 +1,47 @@
/*
* Copyright 2022 James Lyne
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { mount } from '@vue/test-utils';
import PlayerImage from '@/Components/PlayerImage.vue';
import {getDefaultPlayerImage, getPlayerImage} from "@/util/images";
import {useTestImageProvider} from "../helpers";
describe('PlayerImage', async () => {
it('exists', () => {
expect(PlayerImage).toBeTruthy()
});
const player = {
name: 'gamer',
displayName: 'Gamer',
armor: 10,
health: 10,
sort: 1,
hidden: false,
location: {
x: 0,
y: 0,
z: 0,
}
},
wrapper = mount(PlayerImage, {
props: { player },
});
it('displays the default image', () => {
expect(wrapper.element.getAttribute('src')).toEqual(getDefaultPlayerImage())
});
});

View File

@ -0,0 +1,105 @@
/*
* Copyright 2022 James Lyne
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// @vitest-environment jsdom
import {mount, VueWrapper} from '@vue/test-utils';
import Sidebar from '@/Components/Sidebar.vue';
import {addDynmapServer, addWorld, clearServers, clearWorlds, enablePlayerMarkers} from "../helpers";
import {nextTick} from "vue";
import {useStore} from "@/store";
import {MutationTypes} from "@/store/mutation-types";
describe('Sidebar', () => {
it('exists', () => {
expect(Sidebar).toBeTruthy()
});
let component: VueWrapper;
beforeEach(async () => {
clearServers();
clearWorlds();
//Add single dynmap server with single world
addDynmapServer(true);
addWorld('overworld', 1);
const host = document.createElement('div');
document.body.appendChild(host);
component = mount(Sidebar, {
attachTo: host,
});
useStore().commit(MutationTypes.SET_LOADED, undefined);
await nextTick();
});
describe('Maps button', () => {
it('not shown when single map and server exist', () =>
expect(component.find({ref: 'maps-button'}).exists()).toBeFalsy());
it('shown with server icon when multiple servers exist with single map', async () => {
addDynmapServer(false); //Extra server
await nextTick();
expect(component.find({ref: 'maps-button'}).exists()).toBeTruthy();
expect(component.getComponent({ref: 'maps-icon'}).props('name')).toBe("servers");
});
it('shown with map icon when multiple worlds defined', async () => {
addWorld('overworld', 1); //Extra world
await nextTick();
expect(component.find({ref: 'maps-button'}).exists()).toBeTruthy();
expect(component.getComponent({ref: 'maps-icon'}).props('name')).toBe("maps");
});
it('shown with map icon when single world with multiple maps defined', async () => {
clearWorlds();
addWorld('overworld', 2); //World with 2 maps
await nextTick();
expect(component.find({ref: 'maps-button'}).exists()).toBeTruthy();
expect(component.getComponent({ref: 'maps-icon'}).props('name')).toBe("maps");
});
});
describe('Players button', () => {
it('not shown when player markers are disabled', () => {
expect(component.find({ref: 'players-button'}).exists()).toBeFalsy();
});
it('shown when player markers are enabled', async () => {
enablePlayerMarkers();
await nextTick();
expect(component.find({ref: 'players-button'}).exists()).toBeTruthy();
});
it('moves focus to players section on down arrow press', async () => {
const button = component.find({ref: 'players-button'});
(button.element as HTMLElement).focus();
await button.trigger('keydown', {key: 'ArrowDown'})
expect(document.activeElement!.id).toEqual('players-heading');
});
});
});

View File

@ -0,0 +1,60 @@
/*
* Copyright 2022 James Lyne
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { mount } from '@vue/test-utils';
import SVGIcon from '@/Components/SVGIcon.vue';
describe('SVGIcon', async () => {
it('exists', () => {
expect(SVGIcon).toBeTruthy()
});
const wrapper = mount(SVGIcon, {
props: {
name: 'maps',
},
});
it('displays the correct icon', () => {
expect(wrapper.find('use').attributes().href).toEqual('#icon--maps');
});
it('has the correct classname', () => {
expect(wrapper.element.classList.contains('svg-icon--maps')).toBeTruthy();
});
it('displays the correct icon when updated', async () => {
await wrapper.setProps({
name: 'servers',
});
expect(wrapper.find('use').attributes().href).toEqual('#icon--servers');
});
it('has the correct classname when updated', () => {
expect(wrapper.element.classList.contains('svg-icon--servers')).toBeTruthy();
});
it('doesn\'t render <title> when not provided', () => {
expect(wrapper.find('title').exists()).toBeFalsy();
});
it('renders <title> when provided', async () => {
await wrapper.setProps({
title: 'test icon title',
});
expect(wrapper.text()).toContain('test icon title');
});
});

182
test/helpers.ts Normal file
View File

@ -0,0 +1,182 @@
/*
* Copyright 2022 James Lyne
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {useStore} from "@/store";
import {MutationTypes} from "@/store/mutation-types";
import {getDefaultPlayerImage} from "@/util/images";
import {LiveAtlasDimension, LiveAtlasWorldDefinition, PlayerImageQueueEntry} from "../src";
import LiveAtlasMapDefinition from "../src/model/LiveAtlasMapDefinition";
export const enablePlayerMarkers = () => {
useStore().commit(MutationTypes.SET_COMPONENTS, {
players: {
markers: {
hideByDefault: false,
layerName: 'Players',
imageSize: 'large',
layerPriority: 0,
showHealth: true,
showArmor: true,
showYaw: false,
},
showImages: true,
grayHiddenPlayers: true,
imageUrl: getDefaultPlayerImage,
}
});
};
/**
* Clears any test servers added to the store
*/
export const clearServers = () => {
useStore().commit(MutationTypes.SET_SERVERS, new Map());
};
/**
* Adds a test Dynmap server definition to the store, optionally setting it as the current server
* @param setAsCurrent
*/
export const addDynmapServer = (setAsCurrent: boolean) => {
const store = useStore(),
servers = new Map(store.state.servers),
id = `dynmap_${servers.size}`;
servers.set(id, {
id,
label: `Dynmap ${servers.size}`,
dynmap: {
configuration: 'configuration',
update: 'update',
sendmessage: 'sendMessage',
login: 'login',
register: 'register',
tiles: 'tiles',
markers: 'markers',
}
})
useStore().commit(MutationTypes.SET_SERVERS, servers);
if(setAsCurrent) {
useStore().commit(MutationTypes.SET_CURRENT_SERVER, id);
}
};
/**
* Adds a test Pl3xmap server definition to the store, optionally setting it as the current server
* @param setAsCurrent
*/
export const addPl3xmapServer = (setAsCurrent: boolean) => {
const store = useStore(),
servers = new Map(store.state.servers),
id = `pl3xmap_${servers.size}`;
servers.set(id, {
id,
label: `Pl3xmap ${servers.size}`,
pl3xmap: 'pl3xmap',
});
useStore().commit(MutationTypes.SET_SERVERS, servers);
if(setAsCurrent) {
useStore().commit(MutationTypes.SET_CURRENT_SERVER, id);
}
};
/**
* Adds a test Overviewer server definition to the store, optionally setting it as the current server
* @param setAsCurrent
*/
export const addOverviewerServer = (setAsCurrent: boolean) => {
const store = useStore(),
servers = new Map(store.state.servers),
id = `overviewer_${servers.size}`;
servers.set(id, {
id,
label: `Overviewer ${servers.size}`,
overviewer: 'overviewer',
});
useStore().commit(MutationTypes.SET_SERVERS, servers);
if(setAsCurrent) {
useStore().commit(MutationTypes.SET_CURRENT_SERVER, id);
}
};
/**
* Clears any test worlds added to the store
*/
export const clearWorlds = () => {
useStore().commit(MutationTypes.SET_WORLDS, [])
}
/**
* Adds a test world to the store with the given dimension and number of test maps
* @param dimension
* @param mapCount
*/
export const addWorld = (dimension: LiveAtlasDimension, mapCount: number) => {
const store = useStore(),
worlds = [...store.state.worlds.values()],
world: LiveAtlasWorldDefinition = {
name: `${dimension}_${worlds.length}`,
displayName: `${dimension} ${worlds.length}`,
dimension,
seaLevel: 64,
maps: new Set()
};
for(let i = 0; i < mapCount; i++) {
world.maps.add(new LiveAtlasMapDefinition({
name: `map_${i}`,
world,
baseUrl: 'test/',
tileSize: 128,
imageFormat: 'png',
nativeZoomLevels: 1
}));
}
worlds.push(world);
store.commit(MutationTypes.SET_WORLDS, worlds);
};
export const useDefaultImageProvider = () => {
const store = useStore();
store.commit(MutationTypes.SET_COMPONENTS, {
players: Object.assign({
imageUrl: getDefaultPlayerImage
}, store.state.components.players)
});
}
export const useTestImageProvider = (): (entry: PlayerImageQueueEntry) => string => {
const provider = (entry: PlayerImageQueueEntry) => `/test/${entry.name}`,
store = useStore();
store.commit(MutationTypes.SET_COMPONENTS, {
players: Object.assign({
imageUrl: provider
}, store.state.components.players)
});
return provider;
}

View File

@ -14,8 +14,10 @@
* limitations under the License.
*/
import {parseUrl} from "@/util";
import {LiveAtlasParsedUrl} from "@/index";
import {getGlobalMessages, getMessages, getUrlForLocation, guessWorldDimension, parseUrl} from "@/util";
import {LiveAtlasDimension, LiveAtlasGlobalMessageConfig, LiveAtlasMessageConfig, LiveAtlasParsedUrl} from "@/index";
import LiveAtlasMapDefinition from "@/model/LiveAtlasMapDefinition";
import {globalMessages, serverMessages} from "../messages";
const validURLs: [string, URL, LiveAtlasParsedUrl][] = [
[
@ -392,3 +394,72 @@ describe("parseURL", () => {
expect(parseUrl(url)).toEqual(expected);
});
});
describe("guessWorldDimension", () => {
const worlds: [string, LiveAtlasDimension][] = [
['world', 'overworld'],
['smp2022', 'overworld'],
['DIM-1', 'nether'],
['world_nether', 'nether'],
['smp_nether', 'nether'],
['smpnether', 'nether'],
['nether_smp', 'nether'],
['DIM1', 'end'],
['world_the_end', 'end'],
['end', 'end'],
['smp_end', 'end'],
['smpend', 'overworld'], //Would have too many false positives
['end_smp', 'end'],
];
test.each(worlds)('%s -> %s', (input: string, expected: LiveAtlasDimension) =>
expect(guessWorldDimension(input)).toBe(expected))
})
test("getUrlForLocation", () => {
const map = new LiveAtlasMapDefinition({
name: 'test_map',
world: {
name: 'test_world',
displayName: 'Test World',
dimension: 'overworld',
seaLevel: 64,
maps: new Set()
},
baseUrl: 'test/',
tileSize: 128,
imageFormat: 'png',
nativeZoomLevels: 1
});
expect(getUrlForLocation(map, {x: 100, y: 68.5, z: -2300.3}, 3))
.toEqual('#test_world;test_map;100,69,-2300;3')
});
test("getMessages", () => {
const expectedGlobal: LiveAtlasGlobalMessageConfig = globalMessages.reduce((result: any, key) => {
result[key] = `Missing message: ${key}`;
return result;
}, {});
const expectedMessages: LiveAtlasMessageConfig = Object.assign({}, expectedGlobal, serverMessages.reduce((result: any, key) => {
result[key] = `Missing message: ${key}`;
return result;
}, {}));
const input: any = {
extraProperty: true, //Invalid message key
serversHeading: undefined, // Valid message key but undefined
mapTitle: null, // Valid message key but null
loginTitle: '', // Valid message key but empty string
registerConfirmPasswordLabel: {invalid: true}, //Valid message key but not a string,
chatErrorDisabled: 'test defined global message', // Valid global message
chatPlayerQuit: 'test defined server message' // Valid server message
};
expectedGlobal.chatErrorDisabled = expectedMessages.chatErrorDisabled = input.chatErrorDisabled;
expectedMessages.chatPlayerQuit = input.chatPlayerQuit;
expect(getMessages(input)).toEqual(expectedMessages);
expect(getGlobalMessages(input)).toEqual(expectedGlobal);
});