end to end tests for the game page

This commit is contained in:
AlecM33
2022-09-02 15:53:15 -04:00
parent a891251ac7
commit b05afb85ae
32 changed files with 1276 additions and 1585 deletions

View 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 &#128081;</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>&#x1F3C1; 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>`
};

View 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';
}
}

View 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);
}
}

View 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();
}
}