Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"lint": "npx semistandard --fix",
"sass": "sass scss/custom.scss client/style.css --style compressed",
"start": "node server.js",
"test": "node --test",
"webpack": "webpack --config webpack.config.js"
},
"dependencies": {
Expand Down
33 changes: 33 additions & 0 deletions test/get-bonus-part-label.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import test from 'node:test';
import assert from 'node:assert/strict';
import getBonusPartLabel from '../client/scripts/utilities/get-bonus-part-label.js';

test('returns default value and empty difficulty when bonus is undefined', () => {
assert.equal(getBonusPartLabel(undefined, 0), '[10]');
});

test('uses bonus value when present', () => {
const bonus = { values: [15, 10, 5] };
assert.equal(getBonusPartLabel(bonus, 0), '[15]');
assert.equal(getBonusPartLabel(bonus, 2), '[5]');
});

test('uses difficultyModifier when present', () => {
const bonus = { values: [10, 10, 10], difficultyModifiers: ['e', 'm', 'h'] };
assert.equal(getBonusPartLabel(bonus, 0), '[10e]');
assert.equal(getBonusPartLabel(bonus, 2), '[10h]');
});

test('falls back to defaultValue when index has no value', () => {
const bonus = { values: [10] };
assert.equal(getBonusPartLabel(bonus, 5), '[10]');
});

test('uses custom defaultValue and defaultDifficulty', () => {
assert.equal(getBonusPartLabel(undefined, 0, 20, 'e'), '[20e]');
});

test('returns label with no difficulty when difficultyModifiers absent', () => {
const bonus = { values: [10, 10, 10] };
assert.equal(getBonusPartLabel(bonus, 1), '[10]');
});
43 changes: 43 additions & 0 deletions test/merge-two-sorted-arrays.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import test from 'node:test';
import assert from 'node:assert/strict';
import mergeTwoSortedArrays from '../server/merge-two-sorted-arrays.js';

const byId = x => x.id;
const keepFirst = (a, _b) => a;
const sumValues = (a, b) => ({ id: a.id, v: a.v + b.v });

test('merges two non-overlapping sorted arrays', () => {
const a = [{ id: 1 }, { id: 3 }];
const b = [{ id: 2 }, { id: 4 }];
const result = mergeTwoSortedArrays(a, b, byId, keepFirst);
assert.deepEqual(result.map(x => x.id), [1, 2, 3, 4]);
});

test('combines elements with duplicate keys via combineFunction', () => {
const a = [{ id: 1, v: 10 }, { id: 2, v: 20 }];
const b = [{ id: 2, v: 5 }, { id: 3, v: 30 }];
const result = mergeTwoSortedArrays(a, b, byId, sumValues);
assert.deepEqual(result, [{ id: 1, v: 10 }, { id: 2, v: 25 }, { id: 3, v: 30 }]);
});

test('returns copy of array1 when array2 is empty', () => {
const a = [{ id: 1 }, { id: 2 }];
const result = mergeTwoSortedArrays(a, [], byId, keepFirst);
assert.deepEqual(result.map(x => x.id), [1, 2]);
});

test('returns copy of array2 when array1 is empty', () => {
const b = [{ id: 5 }, { id: 7 }];
const result = mergeTwoSortedArrays([], b, byId, keepFirst);
assert.deepEqual(result.map(x => x.id), [5, 7]);
});

test('returns empty array when both inputs are empty', () => {
const result = mergeTwoSortedArrays([], [], byId, keepFirst);
assert.deepEqual(result, []);
});

test('handles single-element arrays', () => {
const result = mergeTwoSortedArrays([{ id: 3 }], [{ id: 1 }], byId, keepFirst);
assert.deepEqual(result.map(x => x.id), [1, 3]);
});
55 changes: 55 additions & 0 deletions test/strings.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import test from 'node:test';
import assert from 'node:assert/strict';
import { escapeHTML, kebabCase, removeParentheses, titleCase } from '../client/scripts/utilities/strings.js';

test('escapeHTML escapes &, <, >, ", and single quotes', () => {
assert.equal(escapeHTML('a & b'), 'a &amp; b');
assert.equal(escapeHTML('<b>bold</b>'), '&lt;b&gt;bold&lt;/b&gt;');
assert.equal(escapeHTML('"quoted"'), '&quot;quoted&quot;');
assert.equal(escapeHTML("it's"), 'it&#039;s');
});

test('escapeHTML returns undefined for undefined input', () => {
assert.equal(escapeHTML(undefined), undefined);
});

test('escapeHTML returns empty string unchanged', () => {
assert.equal(escapeHTML(''), '');
});

test('kebabCase converts spaces to hyphens and lowercases', () => {
assert.equal(kebabCase('Hello World'), 'hello-world');
assert.equal(kebabCase('multiple spaces'), 'multiple-spaces');
assert.equal(kebabCase('ALLCAPS'), 'allcaps');
});

test('kebabCase handles already-lowercase single word', () => {
assert.equal(kebabCase('hello'), 'hello');
});

test('removeParentheses removes round parens content', () => {
// The function removes the parens and their content but does not collapse
// the surrounding spaces — a trailing trim is the only whitespace cleanup.
assert.equal(removeParentheses('foo (bar) baz'), 'foo baz');
});

test('removeParentheses removes square bracket content', () => {
assert.equal(removeParentheses('foo [bar] baz'), 'foo baz');
});

test('removeParentheses trims surrounding whitespace', () => {
assert.equal(removeParentheses(' hello '), 'hello');
});

test('removeParentheses returns string unchanged when no parens', () => {
assert.equal(removeParentheses('plain string'), 'plain string');
});

test('titleCase capitalises first letter of each word', () => {
assert.equal(titleCase('hello-world'), 'Hello World');
assert.equal(titleCase('foo-bar-baz'), 'Foo Bar Baz');
});

test('titleCase handles single word without hyphen', () => {
assert.equal(titleCase('hello'), 'Hello');
});
Loading