Skip to content

Commit 902b706

Browse files
Increase unit test coverage of site scripts (#44)
* Update jest.config.js Add option script to run unit tests only, or all tests. The former is to be able to easily an quickly run unit tests without having to wait for integration tests. When all tests are run, Jest will fail upon the first failed test to avoid running unnecessary and costly integration tests. Also updated the Contributing Guidelines and CI configuration accordingly. * Run unit tests before pushing * Add test suite for color-scheme.js * Add test suite for copy.js * Add test suite for ordering.js * Add test suite for storage.js * Add test suite for search.js * Unskip tests in utils.js suite * Reduce load time of color-scheme.js without storage This change achieves two things: - Not store anything if nothing is stored yet - Don't do anything if stored value matches the default * Reduce load time of ordering.js without storage This change achieves two things: - Not store anything if nothing is stored yet - Don't do anything if stored value matches the default
1 parent 6bcf096 commit 902b706

22 files changed

+892
-59
lines changed

.github/workflows/verify.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ jobs:
4343
- name: Install dependencies
4444
run: npm ci
4545
- name: Run tests
46-
run: npm run test
46+
run: npm run test:all
4747
- name: Upload test screenshots
4848
uses: actions/upload-artifact@v2
4949
with:

.husky/pre-push

+1
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@
44
git stash -q --keep-index
55
npm run lint
66
npm run build
7+
npm run test:unit
78
git stash pop -q || true

CONTRIBUTING.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ The repository defines the following commands that can be used for development p
3838
| `npm run lint` | Lint the source code of the project. |
3939
| `npm run serve` | Serve the files in the `_site/` directory. |
4040
| `npm run serve:watch` | Run `build:watch` and `serve` in parallel. |
41-
| `npm run test` | Run the test suites for the website. |
41+
| `npm run test:all` | Run all unit & integration test suites. (**warning**: slow) |
42+
| `npm run test:unit` | Run all unit test suites. |
4243

4344
### Using Docker
4445

jest.config.js

+29-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,36 @@
1+
const { execSync } = require('child_process');
12
const path = require('path');
23

4+
const TEST_ENV_ALL = 'all';
5+
const TEST_ENV_UNIT = 'unit';
6+
const TEST_ENV_OPTIONS = [TEST_ENV_ALL, TEST_ENV_UNIT];
7+
8+
let bail = 0;
9+
let preset = undefined;
10+
let ignorePaths = ['/node_modules/'];
11+
12+
switch (process.env.TEST_ENV) {
13+
case TEST_ENV_ALL:
14+
console.info('building website for integration tests...');
15+
execSync('npm run clean');
16+
execSync('npm run build:dev');
17+
18+
bail = 1; // Fail immediately to avoid running costly tests unnecessarily
19+
preset = 'jest-puppeteer';
20+
break;
21+
case TEST_ENV_UNIT:
22+
ignorePaths.push('integration.test.js');
23+
break;
24+
default:
25+
console.info(`[ERROR] please set TEST_ENV to one of [${TEST_ENV_OPTIONS}]`);
26+
process.exit(1);
27+
}
28+
329
module.exports = {
4-
preset: 'jest-puppeteer',
30+
bail,
31+
preset,
532
globals: {
633
ARTIFACTS_DIR: path.resolve(__dirname, 'tests/_artifacts'),
734
},
35+
testPathIgnorePatterns: ignorePaths,
836
};

package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@
2020
"format": "prettier --write --single-quote --trailing-comma all .",
2121
"lint": "prettier --check --single-quote --trailing-comma all .",
2222
"postinstall": "is-ci || husky install",
23-
"pretest": "npm run clean && npm run build:dev",
2423
"serve": "anywhere -p 8080 -d ./_site",
2524
"serve:watch": "run-p build:watch serve",
26-
"test": "jest"
25+
"test:all": "TEST_ENV=all jest",
26+
"test:unit": "TEST_ENV=unit jest"
2727
},
2828
"dependencies": {
2929
"simple-icons": "4.9.0",

public/index.pug

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ html
2727
link(rel="mask-icon" href="https://simpleicons.org/images/logo.svg" color="#111111")
2828
link(rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Open+Sans:wght@600&family=Roboto+Mono:wght@400;600&display=swap")
2929

30-
body(class="no-js")
30+
body(class="no-js order-alphabetically")
3131
div(class="banner-feedback" role="banner")
3232
span #[a(href="https://github.com/simple-icons/simple-icons/discussions/4865" rel="noopener") Share your opinion of the redesign on GitHub] or #[a(href="https://simpleicons.org/" rel="noopener") Go to the old design]
3333
span(class="banner__hide") Hide this message #[button(id="hide-feedback-banner-once" disabled) Once] or #[button(id="hide-feedback-banner" disabled) Always]

public/scripts/color-scheme.js

+12-16
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ const DEFAULT_COLOR_SCHEME = COLOR_SCHEME_SYSTEM;
99
const CLASS_DARK_MODE = 'dark';
1010
const CLASS_LIGHT_MODE = 'light';
1111

12-
let activeColorScheme = DEFAULT_COLOR_SCHEME;
13-
1412
export default function initColorScheme(document, storage) {
13+
let activeColorScheme = DEFAULT_COLOR_SCHEME;
14+
1515
const $body = document.querySelector('body');
1616
const $colorSchemeDark = document.getElementById('color-scheme-dark');
1717
const $colorSchemeLight = document.getElementById('color-scheme-light');
@@ -24,33 +24,29 @@ export default function initColorScheme(document, storage) {
2424
const storedColorScheme = storage.getItem(STORAGE_KEY_COLOR_SCHEME);
2525
if (storedColorScheme) {
2626
selectColorScheme(storedColorScheme);
27-
} else {
28-
selectColorScheme(DEFAULT_COLOR_SCHEME);
2927
}
3028

3129
$colorSchemeDark.addEventListener('click', (event) => {
3230
event.preventDefault();
33-
if (activeColorScheme != COLOR_SCHEME_DARK) {
34-
selectColorScheme(COLOR_SCHEME_DARK);
35-
$colorSchemeDark.blur();
36-
}
31+
selectColorScheme(COLOR_SCHEME_DARK);
32+
$colorSchemeDark.blur();
3733
});
3834
$colorSchemeLight.addEventListener('click', (event) => {
3935
event.preventDefault();
40-
if (activeColorScheme != COLOR_SCHEME_LIGHT) {
41-
selectColorScheme(COLOR_SCHEME_LIGHT);
42-
$colorSchemeLight.blur();
43-
}
36+
selectColorScheme(COLOR_SCHEME_LIGHT);
37+
$colorSchemeLight.blur();
4438
});
4539
$colorSchemeSystem.addEventListener('click', (event) => {
4640
event.preventDefault();
47-
if (activeColorScheme != COLOR_SCHEME_SYSTEM) {
48-
selectColorScheme(COLOR_SCHEME_SYSTEM);
49-
$colorSchemeSystem.blur();
50-
}
41+
selectColorScheme(COLOR_SCHEME_SYSTEM);
42+
$colorSchemeSystem.blur();
5143
});
5244

5345
function selectColorScheme(selected) {
46+
if (selected === activeColorScheme) {
47+
return;
48+
}
49+
5450
if (selected === COLOR_SCHEME_DARK) {
5551
$body.classList.add(CLASS_DARK_MODE);
5652
$body.classList.remove(CLASS_LIGHT_MODE);

public/scripts/index.js

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
import '../stylesheet.css';
22

3+
import * as domUtils from './dom-utils.js';
4+
import newStorage from './storage.js';
5+
36
import initCopyButtons from './copy.js';
47
import initColorScheme from './color-scheme.js';
58
import initOrdering from './ordering.js';
69
import initSearch from './search.js';
710
import initFeedbackRequest from './feedback-request.js';
8-
import newStorage from './storage.js';
911

1012
document.body.classList.remove('no-js');
1113

1214
const storage = newStorage(localStorage);
1315
initColorScheme(document, storage);
1416
initCopyButtons(document, navigator);
1517
const orderingControls = initOrdering(document, storage);
16-
initSearch(window.history, document, orderingControls);
18+
initSearch(window.history, document, orderingControls, domUtils);
1719
initFeedbackRequest(document, storage);

public/scripts/ordering.js

+13-17
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ const CLASS_ORDER_ALPHABETICALLY = 'order-alphabetically';
1010
const CLASS_ORDER_BY_COLOR = 'order-by-color';
1111
const CLASS_ORDER_BY_RELEVANCE = 'order-by-relevance';
1212

13-
let activeOrdering = DEFAULT_ORDERING;
14-
let preferredOrdering = DEFAULT_ORDERING;
15-
1613
export default function initOrdering(document, storage) {
14+
let activeOrdering = DEFAULT_ORDERING;
15+
let preferredOrdering = DEFAULT_ORDERING;
16+
1717
const $body = document.querySelector('body');
1818
const $orderAlphabetically = document.getElementById('order-alpha');
1919
const $orderByColor = document.getElementById('order-color');
@@ -26,37 +26,33 @@ export default function initOrdering(document, storage) {
2626
const storedOrdering = storage.getItem(STORAGE_KEY_ORDERING);
2727
if (storedOrdering) {
2828
selectOrdering(storedOrdering);
29-
} else {
30-
selectOrdering(DEFAULT_ORDERING);
3129
}
3230

3331
$orderAlphabetically.addEventListener('click', (event) => {
3432
event.preventDefault();
35-
if (activeOrdering != ORDER_ALPHABETICALLY) {
36-
selectOrdering(ORDER_ALPHABETICALLY);
37-
$orderAlphabetically.blur();
38-
}
33+
selectOrdering(ORDER_ALPHABETICALLY);
34+
$orderAlphabetically.blur();
3935
});
4036
$orderByColor.addEventListener('click', (event) => {
4137
event.preventDefault();
42-
if (activeOrdering != ORDER_BY_COLOR) {
43-
selectOrdering(ORDER_BY_COLOR);
44-
$orderByColor.blur();
45-
}
38+
selectOrdering(ORDER_BY_COLOR);
39+
$orderByColor.blur();
4640
});
4741
$orderByRelevance.addEventListener('click', (event) => {
4842
event.preventDefault();
49-
if (activeOrdering != ORDER_BY_RELEVANCE) {
50-
selectOrdering(ORDER_BY_RELEVANCE);
51-
$orderByRelevance.blur();
52-
}
43+
selectOrdering(ORDER_BY_RELEVANCE);
44+
$orderByRelevance.blur();
5345
});
5446

5547
function currentOrderingIs(value) {
5648
return activeOrdering === value;
5749
}
5850

5951
function selectOrdering(selected) {
52+
if (selected === activeOrdering) {
53+
return;
54+
}
55+
6056
$body.classList.remove(
6157
CLASS_ORDER_ALPHABETICALLY,
6258
CLASS_ORDER_BY_COLOR,

public/scripts/search.js

+16-17
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
1-
import { hideElement, showElement } from './dom-utils.js';
21
import { ORDER_BY_RELEVANCE } from './ordering.js';
32
import { decodeURIComponent, debounce, normalizeSearchTerm } from './utils.js';
43

54
const QUERY_PARAMETER = 'q';
65

7-
let activeQuery = '';
8-
9-
function getQueryFromParameter(parameter) {
6+
function getQueryFromParameter(location, parameter) {
107
const expr = new RegExp(`[\\?&]${parameter}=([^&#]*)`);
118
const results = expr.exec(location.search);
129
if (results !== null) {
@@ -45,12 +42,14 @@ function setSearchQueryInURL(history, path, query) {
4542
}
4643
}
4744

48-
export default function initSearch(history, document, ordering) {
45+
export default function initSearch(history, document, ordering, domUtils) {
46+
let activeQuery = '';
47+
4948
const $searchInput = document.getElementById('search-input');
5049
const $searchClear = document.getElementById('search-clear');
5150
const $orderByRelevance = document.getElementById('order-relevance');
5251
const $gridItemIfEmpty = document.querySelector('.grid-item--if-empty');
53-
const $adSpace = document.querySelector('#carbonads');
52+
const $adSpace = document.getElementById('carbonads');
5453
const $icons = document.querySelectorAll('.grid-item[data-brand]');
5554

5655
$searchInput.disabled = false;
@@ -71,7 +70,7 @@ export default function initSearch(history, document, ordering) {
7170
});
7271

7372
// Load search query if present
74-
const query = getQueryFromParameter(QUERY_PARAMETER);
73+
const query = getQueryFromParameter(document.location, QUERY_PARAMETER);
7574
if (query) {
7675
$searchInput.value = query;
7776
search(query);
@@ -81,16 +80,16 @@ export default function initSearch(history, document, ordering) {
8180
setSearchQueryInURL(history, document.location.pathname, rawQuery);
8281
const query = normalizeSearchTerm(rawQuery);
8382
if (query !== '') {
84-
showElement($searchClear);
85-
showElement($orderByRelevance);
86-
hideElement($adSpace);
83+
domUtils.showElement($searchClear);
84+
domUtils.showElement($orderByRelevance);
85+
domUtils.hideElement($adSpace);
8786
if (activeQuery === '') {
8887
ordering.selectOrdering(ORDER_BY_RELEVANCE);
8988
}
9089
} else {
91-
hideElement($searchClear);
92-
hideElement($orderByRelevance);
93-
showElement($adSpace);
90+
domUtils.hideElement($searchClear);
91+
domUtils.hideElement($orderByRelevance);
92+
domUtils.showElement($adSpace);
9493
if (ordering.currentOrderingIs(ORDER_BY_RELEVANCE)) {
9594
ordering.resetOrdering();
9695
}
@@ -102,18 +101,18 @@ export default function initSearch(history, document, ordering) {
102101
const score = getScore(query, brandName);
103102
if (score < 0) {
104103
$icon.style.removeProperty('--order-relevance');
105-
hideElement($icon);
104+
domUtils.hideElement($icon);
106105
} else {
107106
$icon.style.setProperty('--order-relevance', score);
108-
showElement($icon);
107+
domUtils.showElement($icon);
109108
noResults = false;
110109
}
111110
});
112111

113112
if (noResults) {
114-
showElement($gridItemIfEmpty);
113+
domUtils.showElement($gridItemIfEmpty);
115114
} else {
116-
hideElement($gridItemIfEmpty);
115+
domUtils.hideElement($gridItemIfEmpty);
117116
}
118117

119118
activeQuery = query;

0 commit comments

Comments
 (0)