Compare commits

..

3 Commits

Author SHA1 Message Date
hgw
411e3d38e0
Remove emoji autocompletion 2023-12-03 03:39:40 +00:00
hgw
9d12853be0
have both image and build uncommented 2023-12-03 03:39:03 +00:00
hgw
89cbc770de
add oled.css to build test 2023-12-03 03:38:40 +00:00
4 changed files with 239 additions and 172 deletions

View File

@ -9,9 +9,10 @@
<h2 class="help-version-title"> <h2 class="help-version-title">
<span>About Hard Lounge</span> <span>About Hard Lounge</span>
<small> <small>
v{{ store.state.serverConfiguration?.version }} (<router-link v{{
id="view-changelog" store.state.serverConfiguration?.version
to="/changelog" }}
(<router-link id="view-changelog" to="/changelog"
>release notes</router-link >release notes</router-link
>) >)
</small> </small>
@ -53,8 +54,8 @@
<div class="help-item"> <div class="help-item">
<div class="description"> <div class="description">
<p> <p>
IRC.SUPERNETS.ORG #SUPERBOWL FUCK YOUR NETWORK COLD HARD CHATS THIS IS NOT IRC.SUPERNETS.ORG #SUPERBOWL FUCK YOUR NETWORK COLD HARD
YOUR DADS FOOTBALL CHANNEL CHATS THIS IS NOT YOUR DADS FOOTBALL CHANNEL
</p> </p>
</div> </div>
</div> </div>
@ -93,7 +94,9 @@
<div class="help-item"> <div class="help-item">
<div class="subject"> <div class="subject">
<span v-if="!isApple"><kbd>Alt</kbd> <kbd>Shift</kbd> <kbd></kbd></span> <span v-if="!isApple"
><kbd>Alt</kbd> <kbd>Shift</kbd> <kbd></kbd></span
>
<span v-else><kbd></kbd> <kbd></kbd> <kbd></kbd></span> <span v-else><kbd></kbd> <kbd></kbd> <kbd></kbd></span>
</div> </div>
<div class="description"> <div class="description">
@ -103,7 +106,9 @@
<div class="help-item"> <div class="help-item">
<div class="subject"> <div class="subject">
<span v-if="!isApple"><kbd>Alt</kbd> <kbd>Shift</kbd> <kbd></kbd></span> <span v-if="!isApple"
><kbd>Alt</kbd> <kbd>Shift</kbd> <kbd></kbd></span
>
<span v-else><kbd></kbd> <kbd></kbd> <kbd></kbd></span> <span v-else><kbd></kbd> <kbd></kbd> <kbd></kbd></span>
</div> </div>
<div class="description"> <div class="description">
@ -113,7 +118,9 @@
<div class="help-item"> <div class="help-item">
<div class="subject"> <div class="subject">
<span v-if="!isApple"><kbd>Alt</kbd> <kbd>Shift</kbd> <kbd></kbd></span> <span v-if="!isApple"
><kbd>Alt</kbd> <kbd>Shift</kbd> <kbd></kbd></span
>
<span v-else><kbd></kbd> <kbd></kbd> <kbd></kbd></span> <span v-else><kbd></kbd> <kbd></kbd> <kbd></kbd></span>
</div> </div>
<div class="description"> <div class="description">
@ -123,7 +130,9 @@
<div class="help-item"> <div class="help-item">
<div class="subject"> <div class="subject">
<span v-if="!isApple"><kbd>Alt</kbd> <kbd>Shift</kbd> <kbd></kbd></span> <span v-if="!isApple"
><kbd>Alt</kbd> <kbd>Shift</kbd> <kbd></kbd></span
>
<span v-else><kbd></kbd> <kbd></kbd> <kbd></kbd></span> <span v-else><kbd></kbd> <kbd></kbd> <kbd></kbd></span>
</div> </div>
<div class="description"> <div class="description">
@ -217,8 +226,8 @@
</div> </div>
<div class="description"> <div class="description">
<p> <p>
Close current contextual window (context menu, image viewer, topic edit, Close current contextual window (context menu, image
etc) and remove focus from input. viewer, topic edit, etc) and remove focus from input.
</p> </p>
</div> </div>
</div> </div>
@ -232,15 +241,17 @@
</div> </div>
<div class="description"> <div class="description">
<p> <p>
Mark any text typed after this shortcut to be colored. After hitting this Mark any text typed after this shortcut to be colored.
shortcut, enter an integer in the range After hitting this shortcut, enter an integer in the
<code>015</code> to select the desired color, or use the autocompletion range
menu to choose a color name (see below). <code>015</code> to select the desired color, or use
the autocompletion menu to choose a color name (see
below).
</p> </p>
<p> <p>
Background color can be specified by putting a comma and another integer in Background color can be specified by putting a comma and
the range <code>015</code> after the foreground color number another integer in the range <code>015</code> after the
(autocompletion works too). foreground color number (autocompletion works too).
</p> </p>
<p> <p>
A color reference can be found A color reference can be found
@ -326,8 +337,8 @@
</div> </div>
<div class="description"> <div class="description">
<p> <p>
Mark all text typed after this shortcut to be reset to its original Mark all text typed after this shortcut to be reset to
formatting. its original formatting.
</p> </p>
</div> </div>
</div> </div>
@ -335,10 +346,11 @@
<h2>Autocompletion</h2> <h2>Autocompletion</h2>
<p> <p>
To auto-complete nicknames, channels, commands, and emoji, type one of the To auto-complete nicknames, channels and commands, type one of
characters below to open a suggestion list. Use the <kbd></kbd> and the characters below to open a suggestion list. Use the
<kbd></kbd> keys to highlight an item, and insert it by pressing <kbd>Tab</kbd> or <kbd></kbd> and <kbd></kbd> keys to highlight an item, and
<kbd>Enter</kbd> (or by clicking the desired item). insert it by pressing <kbd>Tab</kbd> or <kbd>Enter</kbd> (or by
clicking the desired item).
</p> </p>
<p>Autocompletion can be disabled in settings.</p> <p>Autocompletion can be disabled in settings.</p>
@ -369,18 +381,6 @@
</div> </div>
</div> </div>
<div class="help-item">
<div class="subject">
<code>:</code>
</div>
<div class="description">
<p>
Emoji (note: requires two search characters, to avoid conflicting with
common emoticons like <code>:)</code>)
</p>
</div>
</div>
<h2>Commands</h2> <h2>Commands</h2>
<div class="help-item"> <div class="help-item">
@ -397,7 +397,9 @@
<code>/back</code> <code>/back</code>
</div> </div>
<div class="description"> <div class="description">
<p>Remove your away status (set with <code>/away</code>).</p> <p>
Remove your away status (set with <code>/away</code>).
</p>
</div> </div>
</div> </div>
@ -407,8 +409,8 @@
</div> </div>
<div class="description"> <div class="description">
<p> <p>
Ban (<code>+b</code>) a user from the current channel. This can be a Ban (<code>+b</code>) a user from the current channel.
nickname or a hostmask. This can be a nickname or a hostmask.
</p> </p>
</div> </div>
</div> </div>
@ -428,7 +430,8 @@
</div> </div>
<div class="description"> <div class="description">
<p> <p>
Collapse all previews in the current channel (opposite of Collapse all previews in the current channel (opposite
of
<code>/expand</code>) <code>/expand</code>)
</p> </p>
</div> </div>
@ -440,8 +443,9 @@
</div> </div>
<div class="description"> <div class="description">
<p> <p>
Connect to a new IRC network. If <code>port</code> starts with a Connect to a new IRC network. If
<code>+</code> sign, the connection will be made secure using TLS. <code>port</code> starts with a <code>+</code> sign, the
connection will be made secure using TLS.
</p> </p>
<p>Alias: <code>/server</code></p> <p>Alias: <code>/server</code></p>
</div> </div>
@ -453,7 +457,8 @@
</div> </div>
<div class="description"> <div class="description">
<p> <p>
Send a <abbr title="Client-to-client protocol">CTCP</abbr> Send a
<abbr title="Client-to-client protocol">CTCP</abbr>
request. Read more about this on request. Read more about this on
<a <a
href="https://en.wikipedia.org/wiki/Client-to-client_protocol" href="https://en.wikipedia.org/wiki/Client-to-client_protocol"
@ -471,8 +476,8 @@
</div> </div>
<div class="description"> <div class="description">
<p> <p>
Remove op (<code>-o</code>) from one or several users in the current Remove op (<code>-o</code>) from one or several users in
channel. the current channel.
</p> </p>
</div> </div>
</div> </div>
@ -483,8 +488,8 @@
</div> </div>
<div class="description"> <div class="description">
<p> <p>
Remove voice (<code>-v</code>) from one or several users in the current Remove voice (<code>-v</code>) from one or several users
channel. in the current channel.
</p> </p>
</div> </div>
</div> </div>
@ -494,7 +499,10 @@
<code>/disconnect [message]</code> <code>/disconnect [message]</code>
</div> </div>
<div class="description"> <div class="description">
<p>Disconnect from the current network with an optionally-provided message.</p> <p>
Disconnect from the current network with an
optionally-provided message.
</p>
</div> </div>
</div> </div>
@ -517,8 +525,8 @@
<div class="description"> <div class="description">
<p> <p>
Invite a user to the specified channel. If Invite a user to the specified channel. If
<code>channel</code> is omitted, user will be invited to the current <code>channel</code> is omitted, user will be invited to
channel. the current channel.
</p> </p>
</div> </div>
</div> </div>
@ -529,8 +537,8 @@
</div> </div>
<div class="description"> <div class="description">
<p> <p>
Block any messages from the specified user on the current network. This can Block any messages from the specified user on the
be a nickname or a hostmask. current network. This can be a nickname or a hostmask.
</p> </p>
</div> </div>
</div> </div>
@ -540,7 +548,9 @@
<code>/ignorelist</code> <code>/ignorelist</code>
</div> </div>
<div class="description"> <div class="description">
<p>Load the list of ignored users for the current network.</p> <p>
Load the list of ignored users for the current network.
</p>
</div> </div>
</div> </div>
@ -550,8 +560,8 @@
</div> </div>
<div class="description"> <div class="description">
<p> <p>
Join a channel. Password is only needed in protected channels and can Join a channel. Password is only needed in protected
usually be omitted. channels and can usually be omitted.
</p> </p>
</div> </div>
</div> </div>
@ -571,8 +581,10 @@
</div> </div>
<div class="description"> <div class="description">
<p> <p>
Kick and ban (<code>+b</code>) a user from the current channel. Unlike Kick and ban (<code>+b</code>) a user from the current
<code>/ban</code>, only nicknames (and not host masks) can be used. channel. Unlike
<code>/ban</code>, only nicknames (and not host masks)
can be used.
</p> </p>
</div> </div>
</div> </div>
@ -582,7 +594,9 @@
<code>/list</code> <code>/list</code>
</div> </div>
<div class="description"> <div class="description">
<p>Retrieve a list of available channels on this network.</p> <p>
Retrieve a list of available channels on this network.
</p>
</div> </div>
</div> </div>
@ -592,8 +606,9 @@
</div> </div>
<div class="description"> <div class="description">
<p> <p>
Send an action message to the current channel. Hard Lounge will display it Send an action message to the current channel. Hard
inline, as if the message was posted in the third person. Lounge will display it inline, as if the message was
posted in the third person.
</p> </p>
</div> </div>
</div> </div>
@ -604,9 +619,10 @@
</div> </div>
<div class="description"> <div class="description">
<p> <p>
Set the given flags to the current channel if the active window is a Set the given flags to the current channel if the active
channel, another user if the active window is a private message window, or window is a channel, another user if the active window
yourself if the current window is a server window. is a private message window, or yourself if the current
window is a server window.
</p> </p>
</div> </div>
</div> </div>
@ -626,10 +642,12 @@
</div> </div>
<div class="description"> <div class="description">
<p> <p>
Prevent messages from generating any feedback for a channel. This turns off Prevent messages from generating any feedback for a
the highlight indicator, hides mentions and inhibits push notifications. channel. This turns off the highlight indicator, hides
Muting a network lobby mutes the entire network. Not specifying any channel mentions and inhibits push notifications. Muting a
target mutes the current channel. Revert with <code>/unmute</code>. network lobby mutes the entire network. Not specifying
any channel target mutes the current channel. Revert
with <code>/unmute</code>.
</p> </p>
</div> </div>
</div> </div>
@ -657,7 +675,10 @@
<code>/op nick [...nick]</code> <code>/op nick [...nick]</code>
</div> </div>
<div class="description"> <div class="description">
<p>Give op (<code>+o</code>) to one or several users in the current channel.</p> <p>
Give op (<code>+o</code>) to one or several users in the
current channel.
</p>
</div> </div>
</div> </div>
@ -667,8 +688,9 @@
</div> </div>
<div class="description"> <div class="description">
<p> <p>
Close the specified channel or private message window, or the current Close the specified channel or private message window,
channel if <code>channel</code> is omitted. or the current channel if <code>channel</code> is
omitted.
</p> </p>
<p>Aliases: <code>/close</code>, <code>/leave</code></p> <p>Aliases: <code>/close</code>, <code>/leave</code></p>
</div> </div>
@ -680,8 +702,9 @@
</div> </div>
<div class="description"> <div class="description">
<p> <p>
Leave and immediately rejoin the current channel. Useful to quickly get op Leave and immediately rejoin the current channel. Useful
from ChanServ in an empty channel, for example. to quickly get op from ChanServ in an empty channel, for
example.
</p> </p>
<p>Alias: <code>/cycle</code></p> <p>Alias: <code>/cycle</code></p>
</div> </div>
@ -701,7 +724,10 @@
<code>/quit [message]</code> <code>/quit [message]</code>
</div> </div>
<div class="description"> <div class="description">
<p>Disconnect from the current network with an optional message.</p> <p>
Disconnect from the current network with an optional
message.
</p>
</div> </div>
</div> </div>
@ -739,8 +765,9 @@
</div> </div>
<div class="description"> <div class="description">
<p> <p>
Get the topic in the current channel. If <code>newtopic</code> is specified, Get the topic in the current channel. If
sets the topic in the current channel. <code>newtopic</code> is specified, sets the topic in
the current channel.
</p> </p>
</div> </div>
</div> </div>
@ -751,8 +778,8 @@
</div> </div>
<div class="description"> <div class="description">
<p> <p>
Unban (<code>-b</code>) a user from the current channel. This can be a Unban (<code>-b</code>) a user from the current channel.
nickname or a hostmask. This can be a nickname or a hostmask.
</p> </p>
</div> </div>
</div> </div>
@ -763,8 +790,8 @@
</div> </div>
<div class="description"> <div class="description">
<p> <p>
Unblock messages from the specified user on the current network. This can be Unblock messages from the specified user on the current
a nickname or a hostmask. network. This can be a nickname or a hostmask.
</p> </p>
</div> </div>
</div> </div>
@ -775,8 +802,9 @@
</div> </div>
<div class="description"> <div class="description">
<p> <p>
Un-mutes the given channel(s) or the current channel if no channel is Un-mutes the given channel(s) or the current channel if
provided. See <code>/mute</code> for more information. no channel is provided. See <code>/mute</code> for more
information.
</p> </p>
</div> </div>
</div> </div>
@ -787,7 +815,8 @@
</div> </div>
<div class="description"> <div class="description">
<p> <p>
Give voice (<code>+v</code>) to one or several users in the current channel. Give voice (<code>+v</code>) to one or several users in
the current channel.
</p> </p>
</div> </div>
</div> </div>
@ -797,7 +826,10 @@
<code>/whois nick</code> <code>/whois nick</code>
</div> </div>
<div class="description"> <div class="description">
<p>Retrieve information about the given user on the current network.</p> <p>
Retrieve information about the given user on the current
network.
</p>
</div> </div>
</div> </div>
@ -1193,8 +1225,8 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import {defineComponent, ref} from "vue"; import { defineComponent, ref } from "vue";
import {useStore} from "../../js/store"; import { useStore } from "../../js/store";
import SidebarToggle from "../SidebarToggle.vue"; import SidebarToggle from "../SidebarToggle.vue";
import VersionChecker from "../VersionChecker.vue"; import VersionChecker from "../VersionChecker.vue";
@ -1206,7 +1238,8 @@ export default defineComponent({
}, },
setup() { setup() {
const store = useStore(); const store = useStore();
const isApple = navigator.platform.match(/(Mac|iPhone|iPod|iPad)/i) || false; const isApple =
navigator.platform.match(/(Mac|iPhone|iPod|iPad)/i) || false;
const isTouch = navigator.maxTouchPoints > 0; const isTouch = navigator.maxTouchPoints > 0;
return { return {

View File

@ -1,35 +1,15 @@
import constants from "./constants"; import constants from "./constants";
import Mousetrap from "mousetrap"; import Mousetrap from "mousetrap";
import {Strategy, Textcomplete, StrategyProps} from "@textcomplete/core"; import { Strategy, Textcomplete, StrategyProps } from "@textcomplete/core";
import {TextareaEditor} from "@textcomplete/textarea"; import { TextareaEditor } from "@textcomplete/textarea";
import fuzzy from "fuzzy"; import fuzzy from "fuzzy";
import emojiMap from "./helpers/simplemap.json"; import { store } from "./store";
import {store} from "./store";
export default enableAutocomplete; export default enableAutocomplete;
const emojiSearchTerms = Object.keys(emojiMap);
const emojiStrategy: StrategyProps = {
id: "emoji",
match: /(^|\s):([-+\w:?]{2,}):?$/,
search(term: string, callback: (matches) => void) {
// Trim colon from the matched term,
// as we are unable to get a clean string from match regex
term = term.replace(/:$/, "");
callback(fuzzyGrep(term, emojiSearchTerms));
},
template([string, original]: [string, string]) {
return `<span class="emoji">${String(emojiMap[original])}</span> ${string}`;
},
replace([, original]: [string, string]) {
return "$1" + String(emojiMap[original]);
},
index: 2,
};
const nicksStrategy: StrategyProps = { const nicksStrategy: StrategyProps = {
id: "nicks", id: "nicks",
match: /(^|\s)(@([a-zA-Z_[\]\\^{}|`@][a-zA-Z0-9_[\]\\^{}|`-]*)?)$/, match: /(^|\s)(@([a-zA-Z_[\]\\^{}|`@][a-zA-Z0-9_[\]\\^{}|`-]*)?)$/,
@ -39,7 +19,12 @@ const nicksStrategy: StrategyProps = {
if (term[0] === "@") { if (term[0] === "@") {
// TODO: type // TODO: type
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands // eslint-disable-next-line @typescript-eslint/restrict-plus-operands
callback(completeNicks(term.slice(1), true).map((val) => ["@" + val[0], "@" + val[1]])); callback(
completeNicks(term.slice(1), true).map((val) => [
"@" + val[0],
"@" + val[1],
])
);
} else { } else {
callback(completeNicks(term, true)); callback(completeNicks(term, true));
} }
@ -108,7 +93,9 @@ const foregroundColorStrategy: StrategyProps = {
callback(matchingColorCodes); callback(matchingColorCodes);
}, },
template(value: string[]) { template(value: string[]) {
return `<span class="irc-fg${parseInt(value[0], 10)}">${value[1]}</span>`; return `<span class="irc-fg${parseInt(value[0], 10)}">${
value[1]
}</span>`;
}, },
replace(value: string) { replace(value: string) {
return "\x03" + value[0]; return "\x03" + value[0];
@ -119,7 +106,11 @@ const foregroundColorStrategy: StrategyProps = {
const backgroundColorStrategy: StrategyProps = { const backgroundColorStrategy: StrategyProps = {
id: "background-colors", id: "background-colors",
match: /\x03(\d{2}),(\d{0,2}|[A-Za-z ]{0,10})$/, match: /\x03(\d{2}),(\d{0,2}|[A-Za-z ]{0,10})$/,
search(term: string, callback: (matchingColorCodes: string[][]) => void, match: string[]) { search(
term: string,
callback: (matchingColorCodes: string[][]) => void,
match: string[]
) {
term = term.toLowerCase(); term = term.toLowerCase();
const matchingColorCodes = constants.colorCodeMap const matchingColorCodes = constants.colorCodeMap
.filter((i) => fuzzy.test(term, i[0]) || fuzzy.test(term, i[1])) .filter((i) => fuzzy.test(term, i[0]) || fuzzy.test(term, i[1]))
@ -141,10 +132,10 @@ const backgroundColorStrategy: StrategyProps = {
callback(matchingColorCodes); callback(matchingColorCodes);
}, },
template(value: string[]) { template(value: string[]) {
return `<span class="irc-fg${parseInt(value[2], 10)} irc-bg irc-bg${parseInt( return `<span class="irc-fg${parseInt(
value[0], value[2],
10 10
)}">${value[1]}</span>`; )} irc-bg irc-bg${parseInt(value[0], 10)}">${value[1]}</span>`;
}, },
replace(value: string[]) { replace(value: string[]) {
return "\x03$1," + value[0]; return "\x03$1," + value[0];
@ -179,7 +170,9 @@ function enableAutocomplete(input: HTMLTextAreaElement) {
const text = input.value; const text = input.value;
if (tabCount === 0) { if (tabCount === 0) {
lastMatch = text.substring(0, input.selectionStart).split(/\s/).pop() || ""; lastMatch =
text.substring(0, input.selectionStart).split(/\s/).pop() ||
"";
if (lastMatch.length === 0) { if (lastMatch.length === 0) {
return; return;
@ -219,7 +212,6 @@ function enableAutocomplete(input: HTMLTextAreaElement) {
); );
const strategies = [ const strategies = [
emojiStrategy,
nicksStrategy, nicksStrategy,
chanStrategy, chanStrategy,
commandStrategy, commandStrategy,
@ -261,7 +253,10 @@ function replaceNick(original: string, position = 1) {
} }
// If there is whitespace in the input already, append space to nick // If there is whitespace in the input already, append space to nick
if (position > 0 && /\s/.test(store.state.activeChannel?.channel.pendingMessage || "")) { if (
position > 0 &&
/\s/.test(store.state.activeChannel?.channel.pendingMessage || "")
) {
return original + " "; return original + " ";
} }
@ -285,14 +280,19 @@ function rawNicks() {
if (store.state.activeChannel.channel.users.length > 0) { if (store.state.activeChannel.channel.users.length > 0) {
const users = store.state.activeChannel.channel.users.slice(); const users = store.state.activeChannel.channel.users.slice();
return users.sort((a, b) => b.lastMessage - a.lastMessage).map((u) => u.nick); return users
.sort((a, b) => b.lastMessage - a.lastMessage)
.map((u) => u.nick);
} }
const me = store.state.activeChannel.network.nick; const me = store.state.activeChannel.network.nick;
const otherUser = store.state.activeChannel.channel.name; const otherUser = store.state.activeChannel.channel.name;
// If this is a query, add their name to autocomplete // If this is a query, add their name to autocomplete
if (me !== otherUser && store.state.activeChannel.channel.type === "query") { if (
me !== otherUser &&
store.state.activeChannel.channel.type === "query"
) {
return [otherUser, me]; return [otherUser, me];
} }

View File

@ -1,7 +1,7 @@
services: services:
hardlounge: hardlounge:
image: git.supernets.org/supernets/hardlounge:latest image: git.supernets.org/supernets/hardlounge:latest
#build: . build: .
ports: ports:
- "9000:9000" - "9000:9000"
volumes: volumes:

View File

@ -1,4 +1,4 @@
import {expect} from "chai"; import { expect } from "chai";
import fs from "fs"; import fs from "fs";
import path from "path"; import path from "path";
@ -6,68 +6,102 @@ describe("public folder", function () {
const publicFolder = path.join(__dirname, "..", "..", "public"); const publicFolder = path.join(__dirname, "..", "..", "public");
it("font awesome files are copied", function () { it("font awesome files are copied", function () {
expect(fs.existsSync(path.join(publicFolder, "fonts", "fa-solid-900.woff"))).to.be.true; expect(
expect(fs.existsSync(path.join(publicFolder, "fonts", "fa-solid-900.woff2"))).to.be.true; fs.existsSync(path.join(publicFolder, "fonts", "fa-solid-900.woff"))
).to.be.true;
expect(
fs.existsSync(
path.join(publicFolder, "fonts", "fa-solid-900.woff2")
)
).to.be.true;
}); });
it("files in root folder are copied", function () { it("files in root folder are copied", function () {
expect(fs.existsSync(path.join(publicFolder, "favicon.ico"))).to.be.true; expect(fs.existsSync(path.join(publicFolder, "favicon.ico"))).to.be
.true;
expect(fs.existsSync(path.join(publicFolder, "robots.txt"))).to.be.true; expect(fs.existsSync(path.join(publicFolder, "robots.txt"))).to.be.true;
expect(fs.existsSync(path.join(publicFolder, "service-worker.js"))).to.be.true; expect(fs.existsSync(path.join(publicFolder, "service-worker.js"))).to
expect(fs.existsSync(path.join(publicFolder, "thelounge.webmanifest"))).to.be.true; .be.true;
expect(fs.existsSync(path.join(publicFolder, "thelounge.webmanifest")))
.to.be.true;
}); });
it("audio files are copied", function () { it("audio files are copied", function () {
expect(fs.existsSync(path.join(publicFolder, "audio", "pop.wav"))).to.be.true; expect(fs.existsSync(path.join(publicFolder, "audio", "pop.wav"))).to.be
});
it("index HTML file is not copied", function () {
expect(fs.existsSync(path.join(publicFolder, "index.html"))).to.be.false;
expect(fs.existsSync(path.join(publicFolder, "index.html.tpl"))).to.be.false;
});
it("javascript files are built", function () {
expect(fs.existsSync(path.join(publicFolder, "js", "bundle.js"))).to.be.true;
expect(fs.existsSync(path.join(publicFolder, "js", "bundle.vendor.js"))).to.be.true;
});
it("style files are built", function () {
expect(fs.existsSync(path.join(publicFolder, "css", "style.css"))).to.be.true;
expect(fs.existsSync(path.join(publicFolder, "css", "style.css.map"))).to.be.true;
expect(fs.existsSync(path.join(publicFolder, "themes", "default.css"))).to.be.true;
expect(fs.existsSync(path.join(publicFolder, "themes", "morning.css"))).to.be.true;
});
it("style files contain expected content", function (done) {
fs.readFile(path.join(publicFolder, "css", "style.css"), "utf8", function (err, contents) {
expect(err).to.be.null;
expect(contents.includes("var(--body-color)")).to.be.true;
expect(contents.includes("url(../fonts/fa-solid-900.woff2)")).to.be.true;
expect(contents.includes(".tooltipped{position:relative}")).to.be.true;
expect(contents.includes("sourceMappingURL")).to.be.true;
done();
});
});
it("javascript map is created", function () {
expect(fs.existsSync(path.join(publicFolder, "js", "bundle.js.map"))).to.be.true;
});
it("loading-error-handlers.js is copied", function () {
expect(fs.existsSync(path.join(publicFolder, "js", "loading-error-handlers.js"))).to.be
.true; .true;
}); });
it("index HTML file is not copied", function () {
expect(fs.existsSync(path.join(publicFolder, "index.html"))).to.be
.false;
expect(fs.existsSync(path.join(publicFolder, "index.html.tpl"))).to.be
.false;
});
it("javascript files are built", function () {
expect(fs.existsSync(path.join(publicFolder, "js", "bundle.js"))).to.be
.true;
expect(fs.existsSync(path.join(publicFolder, "js", "bundle.vendor.js")))
.to.be.true;
});
it("style files are built", function () {
expect(fs.existsSync(path.join(publicFolder, "css", "style.css"))).to.be
.true;
expect(fs.existsSync(path.join(publicFolder, "css", "style.css.map")))
.to.be.true;
expect(fs.existsSync(path.join(publicFolder, "themes", "default.css")))
.to.be.true;
expect(fs.existsSync(path.join(publicFolder, "themes", "morning.css")))
.to.be.true;
expect(fs.existsSync(path.join(publicFolder, "themes", "oled.css"))).to
.be.true;
});
it("style files contain expected content", function (done) {
fs.readFile(
path.join(publicFolder, "css", "style.css"),
"utf8",
function (err, contents) {
expect(err).to.be.null;
expect(contents.includes("var(--body-color)")).to.be.true;
expect(contents.includes("url(../fonts/fa-solid-900.woff2)")).to
.be.true;
expect(contents.includes(".tooltipped{position:relative}")).to
.be.true;
expect(contents.includes("sourceMappingURL")).to.be.true;
done();
}
);
});
it("javascript map is created", function () {
expect(fs.existsSync(path.join(publicFolder, "js", "bundle.js.map"))).to
.be.true;
});
it("loading-error-handlers.js is copied", function () {
expect(
fs.existsSync(
path.join(publicFolder, "js", "loading-error-handlers.js")
)
).to.be.true;
});
it("service worker has cacheName set", function (done) { it("service worker has cacheName set", function (done) {
fs.readFile(path.join(publicFolder, "service-worker.js"), "utf8", function (err, contents) { fs.readFile(
expect(err).to.be.null; path.join(publicFolder, "service-worker.js"),
"utf8",
function (err, contents) {
expect(err).to.be.null;
expect(contents.includes("const cacheName")).to.be.true; expect(contents.includes("const cacheName")).to.be.true;
expect(contents.includes("__HASH__")).to.be.false; expect(contents.includes("__HASH__")).to.be.false;
done(); done();
}); }
);
}); });
}); });