mirror of
https://github.com/AlecM33/Werewolf.git
synced 2025-12-30 09:47:50 +01:00
end to end tests for the game page
This commit is contained in:
295
client/src/modules/front_end_components/HTMLFragments.js
Normal file
295
client/src/modules/front_end_components/HTMLFragments.js
Normal file
@@ -0,0 +1,295 @@
|
||||
export const HTMLFragments = {
|
||||
LOBBY:
|
||||
`<div id='lobby-header'>
|
||||
<div>
|
||||
<label for='game-link'>Share Link</label>
|
||||
<div tabindex='0' id='game-link'></div>
|
||||
<div id='game-code'></div>
|
||||
</div>
|
||||
<div>
|
||||
<canvas id="canvas"></canvas>
|
||||
<div id='game-parameters'>
|
||||
<div>
|
||||
<img alt='clock' src='/images/clock.svg'/>
|
||||
<div id='game-time'></div>
|
||||
</div>
|
||||
<div>
|
||||
<img alt='person' src='/images/person.svg'/>
|
||||
<div id='game-player-count'></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<button id='role-info-button' class='app-button'>Roles in This Game <img src='/images/info.svg'/></button>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div id='lobby-people-container'>
|
||||
<label for='lobby-players'>Other People</label>
|
||||
<div id='lobby-players'></div>
|
||||
</div>
|
||||
<div id='lobby-footer'>
|
||||
<div id='game-deck'></div>
|
||||
</div>
|
||||
</div>`,
|
||||
ENTER_NAME_STEP:
|
||||
`<div id='step-4'>
|
||||
<div>
|
||||
<input type="text" id="moderator-name" autocomplete='given-name' placeholder="enter your name...">
|
||||
</div>
|
||||
</div>`,
|
||||
START_GAME_PROMPT:
|
||||
`<div>
|
||||
<button id='start-game-button'>Start Game</button>
|
||||
<p>All players must join to start.</p>
|
||||
</div>`,
|
||||
END_GAME_PROMPT:
|
||||
`<div id='end-game-prompt'>
|
||||
<button id='end-game-button'>End Game</button>
|
||||
</div>`,
|
||||
PLAYER_GAME_VIEW:
|
||||
`<div id='game-header'>
|
||||
<div>
|
||||
<label for='game-timer'>Time Remaining</label>
|
||||
<div id='game-timer'></div>
|
||||
</div>
|
||||
<div>
|
||||
<button id='role-info-button' class='app-button'>Roles in This Game <img src='/images/info.svg'/></button>
|
||||
</div>
|
||||
</div>
|
||||
<div id='game-role'>
|
||||
<h4 id='role-name'></h4>
|
||||
<img alt='role' id='role-image'/>
|
||||
<p id='role-description'></p>
|
||||
</div>
|
||||
<div id='game-role-back'>
|
||||
<h4>Double-tap here to show your role</h4>
|
||||
<p>(Double-tap here again to hide)</p>
|
||||
</div>
|
||||
<div id='game-people-container'>
|
||||
<label id='players-alive-label'></label>
|
||||
<div id='game-player-list'></div>
|
||||
</div>`,
|
||||
SPECTATOR_GAME_VIEW:
|
||||
`<div id='game-header'>
|
||||
<div>
|
||||
<label for='game-timer'>Time Remaining</label>
|
||||
<div id='game-timer'></div>
|
||||
</div>
|
||||
<div>
|
||||
<button id='role-info-button' class='app-button'>Roles in This Game <img src='/images/info.svg'/></button>
|
||||
</div>
|
||||
</div>
|
||||
<div id='game-people-container'>
|
||||
<label id='players-alive-label'></label>
|
||||
<div id='game-player-list'></div>
|
||||
</div>`,
|
||||
TRANSFER_MOD_MODAL:
|
||||
`<div id='transfer-mod-modal-background' class='modal-background'></div>
|
||||
<div tabindex='-1' id='transfer-mod-modal' class='modal'>
|
||||
<h3>Transfer Mod Powers 👑</h3>
|
||||
<div id='transfer-mod-modal-content'></div>
|
||||
<div class='modal-button-container'>
|
||||
<button id='close-mod-transfer-modal-button' class='app-button cancel'>Cancel</button>
|
||||
</div>
|
||||
</div>`,
|
||||
MODERATOR_GAME_VIEW:
|
||||
`<div id='game-header'>
|
||||
<div id='timer-container-moderator'>
|
||||
<div>
|
||||
<label for='game-timer'>Time Remaining</label>
|
||||
<div id='game-timer'></div>
|
||||
</div>
|
||||
<div id='play-pause'>
|
||||
<div id="play-pause-placeholder"></div>
|
||||
</div>
|
||||
</div>
|
||||
<button id='mod-transfer-button' class='moderator-player-button make-mod-button app-button'>Transfer Mod Powers \uD83D\uDD00</button>
|
||||
<div>
|
||||
<button id='role-info-button' class='app-button'>Roles in This Game <img src='/images/info.svg'/></button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="game-players-container">
|
||||
<label id='players-alive-label'></label>
|
||||
<div id='game-player-list'>
|
||||
<div class='evil-players'>
|
||||
<label class='evil'>Team Evil</label>
|
||||
<div id='player-list-moderator-team-evil'></div>
|
||||
</div>
|
||||
<div class='good-players'>
|
||||
<label class='good'>Team Good</label>
|
||||
<div id='player-list-moderator-team-good'></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>`,
|
||||
TEMP_MOD_GAME_VIEW:
|
||||
`<div id='game-header'>
|
||||
<div id='timer-container-moderator'>
|
||||
<div>
|
||||
<label for='game-timer'>Time Remaining</label>
|
||||
<div id='game-timer'></div>
|
||||
</div>
|
||||
<div id='play-pause'> </div>
|
||||
</div>
|
||||
<div>
|
||||
<button id='role-info-button' class='app-button'>Roles in This Game <img src='/images/info.svg'/></button>
|
||||
</div>
|
||||
</div>
|
||||
<div id='game-role'>
|
||||
<h4 id='role-name'></h4>
|
||||
<img alt='role' id='role-image'/>
|
||||
<p id='role-description'></p>
|
||||
</div>
|
||||
<div id='game-role-back'>
|
||||
<h4>Double-tap here to show your role</h4>
|
||||
<p>(Double-tap here again to hide)</p>
|
||||
</div>
|
||||
<div id='game-people-container'>
|
||||
<label id='players-alive-label'></label>
|
||||
<div id='game-player-list'></div>
|
||||
</div>
|
||||
</div>`,
|
||||
MODERATOR_PLAYER:
|
||||
`<div>
|
||||
<div class='game-player-name'></div>
|
||||
<div class='game-player-role'></div>
|
||||
</div>
|
||||
<div class='player-action-buttons'>
|
||||
<button title='Kill' class='moderator-player-button kill-player-button'>\uD83D\uDC80</button>
|
||||
<button title='Reveal' class='moderator-player-button reveal-role-button'><img alt='reveal' src='../../images/eye.svg'/></button>
|
||||
</div>`,
|
||||
GAME_PLAYER:
|
||||
`<div>
|
||||
<div class='game-player-name'></div>
|
||||
<div class='game-player-role'></div>
|
||||
</div>`,
|
||||
INITIAL_GAME_DOM:
|
||||
`<div id='game-title'></div>
|
||||
<div id='client-container'>
|
||||
<label for='client'>You</label>
|
||||
<div id='client'>
|
||||
<div id='client-name'></div>
|
||||
<div id='client-user-type'></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id='game-state-container'></div>`,
|
||||
// via https://loading.io/css/
|
||||
SPINNER:
|
||||
`<div class="lds-spinner">
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
</div>`,
|
||||
NAME_CHANGE_MODAL:
|
||||
`<div id='change-name-modal-background' class='modal-background'></div>
|
||||
<div tabindex='-1' id='change-name-modal' class='modal'>
|
||||
<form id='change-name-form'>
|
||||
<div id='transfer-mod-form-content'>
|
||||
<label for='player-new-name'>Your name:</label>
|
||||
<input id='player-new-name' autocomplete='given-name' type='text'/>
|
||||
</div>
|
||||
<div class='modal-button-container'>
|
||||
<input type='submit' id='submit-new-name' value='Set Name'/>
|
||||
</div>
|
||||
</form>
|
||||
</div>`,
|
||||
ROLE_INFO_MODAL:
|
||||
`<div id='role-info-modal-background' class='modal-background'></div>
|
||||
<div tabindex='-1' id='role-info-modal' class='modal'>
|
||||
<h2>Roles in this game:</h2>
|
||||
<div id='game-role-info-container'></div>
|
||||
<div class='modal-button-container'>
|
||||
<button id='close-role-info-modal-button' class='app-button cancel'>Close</button>
|
||||
</div>
|
||||
</div>`,
|
||||
END_OF_GAME_VIEW:
|
||||
`<div id='end-of-game-header'>
|
||||
<h2>🏁 The moderator has ended the game. Roles are revealed.</h2>
|
||||
<div id="end-of-game-buttons">
|
||||
<div>
|
||||
<button id='role-info-button' class='app-button'>Roles in This Game <img src='/images/info.svg'/></button>
|
||||
</div>
|
||||
<div>
|
||||
<a href='/'>
|
||||
<button class='app-button'>Go Home \uD83C\uDFE0</button>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id='game-people-container'>
|
||||
<label id='players-alive-label'></label>
|
||||
<div id='game-player-list'></div>
|
||||
</div>`,
|
||||
RESTART_GAME_BUTTON:
|
||||
'<button id=\'restart-game\' class=\'app-button\'>Restart Game 🔄</button>',
|
||||
CREATE_GAME_DECK:
|
||||
`<div id='deck-container'>
|
||||
<div>
|
||||
<label for='deck-good'>Available Good Roles</label>
|
||||
<div id='deck-good'></div>
|
||||
</div>
|
||||
<div>
|
||||
<label for='deck-evil'>Available Evil Roles</label>
|
||||
<div id='deck-evil'></div>
|
||||
</div>
|
||||
</div>`,
|
||||
DECK_TEMPLATE:
|
||||
`<div class='template-option-name'></div>
|
||||
<div class='template-option-roles'></div>`,
|
||||
CREATE_GAME_CUSTOM_ROLES:
|
||||
`<div id="custom-roles-container">
|
||||
<button id="custom-role-hamburger" class="hamburger hamburger--collapse" type="button">
|
||||
<span class="hamburger-box">
|
||||
<span class="hamburger-inner"></span>
|
||||
</span>
|
||||
</button>
|
||||
<div id="custom-role-actions">
|
||||
<div tabindex="0" class="custom-role-action" id="custom-roles-export">Export Roles</div>
|
||||
<div tabindex="0" class="custom-role-action" id="custom-roles-import">Import Roles</div>
|
||||
</div>
|
||||
<label for="add-card-to-deck-form">Role Box</label>
|
||||
<div id="role-category-buttons">
|
||||
<button id="role-category-default" class="role-category-button role-category-button-selected">Default Roles</button>
|
||||
<button id="role-category-custom" class="role-category-button">Custom Roles</button>
|
||||
</div>
|
||||
<div id="role-select"></div>
|
||||
<button id="custom-role-btn" class="app-button">+ Create Custom Role</button>
|
||||
</div>`,
|
||||
CREATE_GAME_DECK_STATUS:
|
||||
`<div id="deck-status-container">
|
||||
<div id="deck-status-header">
|
||||
<div id="deck-count">0 Players</div>
|
||||
<button id="deck-template-button" class="app-button">Use Template</button>
|
||||
</div>
|
||||
<div id="deck-list"></div>
|
||||
</div>`,
|
||||
DECK_SELECT_ROLE:
|
||||
`<div class="role-name"></div>
|
||||
<div class="role-options">
|
||||
<img tabindex="0" class="role-include" src="images/add.svg" title="add one" alt="add one"/>
|
||||
<img tabindex="0" class="role-info" src="images/info.svg" title="info" alt="info"/>
|
||||
<img tabindex="0" class="role-edit" src="images/pencil.svg" title="edit" alt="edit"/>
|
||||
<img tabindex="0" class="role-remove" src="images/delete.svg" title="remove" alt="remove"/>
|
||||
</div>`,
|
||||
DECK_SELECT_ROLE_DEFAULT:
|
||||
`<div class="role-name"></div>
|
||||
<div class="role-options">
|
||||
<img tabindex="0" class="role-include" src="images/add.svg" title="add one" alt="add one"/>
|
||||
<img tabindex="0" class="role-info" src="images/info.svg" title="info" alt="info"/>
|
||||
</div>`,
|
||||
DECK_SELECT_ROLE_ADDED_TO_DECK:
|
||||
`<div class="role-name"></div>
|
||||
<div class="role-options">
|
||||
<img tabindex="0" class="role-remove" src="images/remove.svg" title="remove one" alt="remove one"/>
|
||||
<img tabindex="0" class="role-info" src="images/info.svg" title="info" alt="info"/>
|
||||
</div>`
|
||||
};
|
||||
34
client/src/modules/front_end_components/ModalManager.js
Normal file
34
client/src/modules/front_end_components/ModalManager.js
Normal file
@@ -0,0 +1,34 @@
|
||||
export const ModalManager = {
|
||||
displayModal: displayModal,
|
||||
dispelModal: dispelModal
|
||||
};
|
||||
|
||||
function displayModal (modalId, backgroundId, closeButtonId) {
|
||||
const modal = document.getElementById(modalId);
|
||||
const modalOverlay = document.getElementById(backgroundId);
|
||||
const closeBtn = document.getElementById(closeButtonId);
|
||||
let closeModalHandler;
|
||||
if (modal && modalOverlay && closeBtn) {
|
||||
modal.style.display = 'flex';
|
||||
modalOverlay.style.display = 'flex';
|
||||
modalOverlay.removeEventListener('click', closeModalHandler);
|
||||
modalOverlay.addEventListener('click', closeModalHandler = function (e) {
|
||||
e.preventDefault();
|
||||
dispelModal(modalId, backgroundId);
|
||||
});
|
||||
closeBtn.removeEventListener('click', closeModalHandler);
|
||||
closeBtn.addEventListener('click', closeModalHandler);
|
||||
} else {
|
||||
throw new Error('One or more of the ids supplied to ModalManager.displayModal is invalid.');
|
||||
}
|
||||
modal.focus();
|
||||
}
|
||||
|
||||
function dispelModal (modalId, backgroundId) {
|
||||
const modal = document.getElementById(modalId);
|
||||
const modalOverlay = document.getElementById(backgroundId);
|
||||
if (modal && modalOverlay) {
|
||||
modal.style.display = 'none';
|
||||
modalOverlay.style.display = 'none';
|
||||
}
|
||||
}
|
||||
55
client/src/modules/front_end_components/Navbar.js
Normal file
55
client/src/modules/front_end_components/Navbar.js
Normal file
@@ -0,0 +1,55 @@
|
||||
export const injectNavbar = (page = null) => {
|
||||
if (document.getElementById('navbar') !== null) {
|
||||
document.getElementById('navbar').innerHTML =
|
||||
"<button name='Mobile Navbar' aria-label='Mobile Navbar' id=\"navbar-hamburger\" class=\"hamburger hamburger--collapse\" type=\"button\">" +
|
||||
'<span class="hamburger-box">' +
|
||||
'<span class="hamburger-inner"></span>' +
|
||||
'</span>' +
|
||||
'</button>' +
|
||||
'<div id="mobile-menu" class="hidden">' +
|
||||
'<div id="mobile-links">' +
|
||||
getNavbarLinks(page, 'mobile') +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</a>' +
|
||||
'<div id="desktop-menu">' +
|
||||
'<div id="desktop-links">' +
|
||||
getNavbarLinks(page, 'desktop') +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div id="navbar-profile"></div>';
|
||||
}
|
||||
attachHamburgerListener();
|
||||
};
|
||||
|
||||
function flipHamburger () {
|
||||
const hamburger = document.getElementById('navbar-hamburger');
|
||||
if (hamburger.classList.contains('is-active')) {
|
||||
hamburger.classList.remove('is-active');
|
||||
document.getElementById('mobile-menu').classList.add('hidden');
|
||||
document.getElementById('mobile-menu-background-overlay').classList.remove('overlay');
|
||||
} else {
|
||||
hamburger.classList.add('is-active');
|
||||
document.getElementById('mobile-menu-background-overlay').classList.add('overlay');
|
||||
document.getElementById('mobile-menu').classList.remove('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
function getNavbarLinks (page = null, device) {
|
||||
const linkClass = device === 'mobile' ? 'mobile-link' : 'desktop-link';
|
||||
return '<a href="/" class="logo ' + linkClass + '">' +
|
||||
'<img alt="logo" src="../../images/Werewolf_Small.png"/>' +
|
||||
'</a>' +
|
||||
'<a class="' + linkClass + '" href="/">Home</a>' +
|
||||
'<a class="' + linkClass + '" href="/create">Create</a>' +
|
||||
'<a class="' + linkClass + '" href="/how-to-use">How to Use</a>' +
|
||||
'<a class="' + linkClass + ' "href="mailto:play.werewolf.contact@gmail.com?Subject=Werewolf App" target="_top">Contact</a>' +
|
||||
'<a class="' + linkClass + ' "href="https://github.com/alecm33/Werewolf" target="_top">Github</a>' +
|
||||
'<a class="' + linkClass + '" href="https://www.buymeacoffee.com/alecm33">Support the App</a>';
|
||||
}
|
||||
|
||||
function attachHamburgerListener () {
|
||||
if (document.getElementById('navbar') !== null && document.getElementById('navbar').style.display !== 'none') {
|
||||
document.getElementById('navbar-hamburger').addEventListener('click', flipHamburger);
|
||||
}
|
||||
}
|
||||
73
client/src/modules/front_end_components/Toast.js
Normal file
73
client/src/modules/front_end_components/Toast.js
Normal file
@@ -0,0 +1,73 @@
|
||||
export const toast = (
|
||||
message,
|
||||
type, positionAtTop = true,
|
||||
dispelAutomatically = true,
|
||||
duration = null,
|
||||
innerHTML = false
|
||||
) => {
|
||||
if (message && type) {
|
||||
buildAndInsertMessageElement(message, type, positionAtTop, dispelAutomatically, duration, innerHTML);
|
||||
}
|
||||
};
|
||||
|
||||
function buildAndInsertMessageElement (message, type, positionAtTop, dispelAutomatically, duration, innerHTML) {
|
||||
cancelCurrentToast();
|
||||
const messageEl = document.createElement('div');
|
||||
messageEl.classList.add('info-message');
|
||||
const positionClass = positionAtTop ? 'toast-top' : 'toast-bottom';
|
||||
messageEl.classList.add(positionClass);
|
||||
switch (type) {
|
||||
case 'warning':
|
||||
messageEl.classList.add('toast-warning');
|
||||
break;
|
||||
case 'error':
|
||||
messageEl.classList.add('toast-error');
|
||||
break;
|
||||
case 'success':
|
||||
messageEl.classList.add('toast-success');
|
||||
break;
|
||||
case 'neutral':
|
||||
messageEl.classList.add('toast-neutral');
|
||||
break;
|
||||
}
|
||||
|
||||
switch (duration) {
|
||||
case null:
|
||||
case undefined:
|
||||
messageEl.classList.add('toast-medium');
|
||||
break;
|
||||
case 'short':
|
||||
messageEl.classList.add('toast-short');
|
||||
break;
|
||||
case 'medium':
|
||||
messageEl.classList.add('toast-medium');
|
||||
break;
|
||||
case 'long':
|
||||
messageEl.classList.add('toast-long');
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (dispelAutomatically) {
|
||||
messageEl.classList.add('toast-dispel-automatically');
|
||||
} else {
|
||||
messageEl.classList.add('toast-not-dispelled-automatically');
|
||||
}
|
||||
|
||||
messageEl.setAttribute('id', 'current-info-message');
|
||||
if (innerHTML) {
|
||||
messageEl.innerHTML = message;
|
||||
} else {
|
||||
messageEl.innerText = message;
|
||||
}
|
||||
|
||||
document.body.prepend(messageEl);
|
||||
}
|
||||
|
||||
export function cancelCurrentToast () {
|
||||
const currentMessage = document.getElementById('current-info-message');
|
||||
if (currentMessage !== null) {
|
||||
currentMessage.remove();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user