Branch data Line data Source code
1 [ + ]: 1 : /**
2 : 1 : * @module utilities-test
3 : 1 : * @desc Testing module for the {@link module:utilities utilities} module.
4 : 1 : * @version 1.0.0
5 : 1 : * @author Essam A. El-Sherif
6 : 1 : */
7 : 1 :
8 : 1 : /* Import node.js core modules */
9 : 1 : import assert from 'node:assert/strict';
10 : 1 :
11 : 1 : /* Import the tested module */
12 : 1 : import {updateObject, isValidObject, extractSubobjectByKeys} from '../lib/utils.js';
13 : 1 :
14 : 1 : /* Prepare test environment */
15 : 1 : let testCount = 1;
16 : 1 : let passCount = 0;
17 : 1 : let failCount = 0;
18 : 1 : let cancelCount = 0;
19 : 1 : let skipCount = 0;
20 : 1 : let todoCount = 0;
21 : 1 : let startTime = Date.now();
22 : 1 :
23 : 1 : const suites = new Map();
24 : 1 :
25 : 1 : /** @const {object} cmdOptions - Testing options. */
26 : 1 : const cmdOptions = {
27 : 1 : node : true,
28 : 1 : verbose : true,
29 : 1 : };
30 : 1 :
31 : 1 : /**
32 : 1 : * @func Main
33 : 1 : * @desc The application entry point function.
34 : 1 : */
35 [ + ]: 1 : (() => {
36 : 1 : loadTestData();
37 : 1 :
38 : 1 : if(cmdOptions.node){
39 : 1 :
40 : 1 : import('node:test')
41 [ + ]: 1 : .then(runner => {
42 : 1 : cmdOptions.verbose = false;
43 : 1 : nodeRunner(runner);
44 : 1 : }) /* node:coverage disable */
45 : : .catch((e) => {
46 : : defRunner();
47 : : });
48 [ - ]: : }
49 : : else{
50 : : defRunner();
51 : : } /* node:coverage enable */
52 : 1 : })('Main Function');
53 : 1 :
54 : 1 : /**
55 : 1 : * @func loadTestData
56 : 1 : * @desc Load test data.
57 : 1 : */
58 [ + ]: 1 : function loadTestData(){
59 : 1 :
60 : 1 : let testData = null;
61 : 1 : let suiteDesc = '';
62 : 1 :
63 : 1 : // TEST SUITE #1 - Test utilities functions
64 : 1 : suiteDesc = 'Test utilities functions';
65 : 1 : suites.set(suiteDesc, []);
66 : 1 :
67 : 1 : // TEST ### - Function updateObject()...test#1
68 : 1 : testData = {};
69 : 1 :
70 [ + ]: 1 : testData.method = async () => {
71 : 1 :
72 : 1 : const originalDict = { name: 'Alice', age: 30, location: 'New York', email: 'alice@example.com' };
73 : 1 : const updatesDict = { name: 'Alice Smith', age: 31, location: 'Los Angeles', email: 'alice.smith@example.com' };
74 : 1 :
75 : 1 : const keysToExclude = ['email'];
76 : 1 : const expectDict = { name: 'Alice Smith', age: 31, location: 'Los Angeles', email: 'alice@example.com' };
77 : 1 :
78 : 1 : updateObject(originalDict, updatesDict, keysToExclude);
79 : 1 : assert.deepStrictEqual(originalDict, expectDict);
80 : 1 : };
81 : 1 : testData.desc = 'Function updateObject()...test#1';
82 : 1 :
83 : 1 : testData.skip = false;
84 : 1 : suites.get(suiteDesc).push(testData);
85 : 1 :
86 : 1 : // TEST ### - Function isValidObject()...test#1
87 : 1 : testData = {};
88 : 1 :
89 [ + ]: 1 : testData.method = async () => {
90 : 1 :
91 : 1 : const validDict = { name: 'Alice', age: 30 };
92 : 1 : const allowedKeys = ['name', 'age', 'email'];
93 : 1 :
94 : 1 : assert(isValidObject(validDict, allowedKeys));
95 : 1 : };
96 : 1 : testData.desc = 'Function isValidObject()...test#1';
97 : 1 :
98 : 1 : testData.skip = false;
99 : 1 : suites.get(suiteDesc).push(testData);
100 : 1 :
101 : 1 : // TEST ### - Function isValidObject()...test#2
102 : 1 : testData = {};
103 : 1 :
104 [ + ]: 1 : testData.method = async () => {
105 : 1 :
106 : 1 : const invalidDict = { name: 'Bob', age: 25, location: 'City' };
107 : 1 : const allowedKeys = ['name', 'age', 'email'];
108 : 1 :
109 : 1 : assert(!isValidObject(invalidDict, allowedKeys));
110 : 1 : };
111 : 1 : testData.desc = 'Function isValidObject()...test#2';
112 : 1 :
113 : 1 : testData.skip = false;
114 : 1 : suites.get(suiteDesc).push(testData);
115 : 1 :
116 : 1 : // TEST ### - Function isValidObject()...test#3
117 : 1 : testData = {};
118 : 1 :
119 [ + ]: 1 : testData.method = async () => {
120 : 1 :
121 : 1 : const notDict = ['name', 'Alice'];
122 : 1 : const allowedKeys = ['name', 'age', 'email'];
123 : 1 :
124 : 1 : assert(!isValidObject(notDict, allowedKeys));
125 : 1 : };
126 : 1 : testData.desc = 'Function isValidObject()...test#3';
127 : 1 :
128 : 1 : testData.skip = false;
129 : 1 : suites.get(suiteDesc).push(testData);
130 : 1 :
131 : 1 : // TEST ### - Function extractSubobjectByKeys()...test#1
132 : 1 : testData = {};
133 : 1 :
134 [ + ]: 1 : testData.method = async () => {
135 : 1 :
136 : 1 : const originalDict = {
137 : 1 : name: 'John Doe',
138 : 1 : age: 30,
139 : 1 : email: 'johndoe@example.com',
140 : 1 : country: 'USA'
141 : 1 : };
142 : 1 : const keysList = ['name', 'email'];
143 : 1 :
144 : 1 : const subDict = extractSubobjectByKeys(originalDict, keysList);
145 : 1 :
146 : 1 : assert.deepStrictEqual(subDict, { name: 'John Doe', email: 'johndoe@example.com' });
147 : 1 : };
148 : 1 : testData.desc = 'Function extractSubobjectByKeys()...test#1';
149 : 1 :
150 : 1 : testData.skip = false;
151 : 1 : suites.get(suiteDesc).push(testData);
152 : 1 : }
153 : 1 :
154 : 1 : /**
155 : 1 : * @func nodeRunner
156 : 1 : * @param {object} runner - The node core module 'node:test' object.
157 : 1 : * @desc Carry out the loaded tests using node test runner.
158 : 1 : */
159 [ + ]: 1 : function nodeRunner(runner){
160 : 1 :
161 : 1 : for(let [suiteDesc, suiteTests] of suites){
162 [ + ]: 1 : runner.suite(suiteDesc, () => {
163 [ + ]: 1 : for(let cmdObj of suiteTests){
164 [ + ]: 5 : runner.test(cmdObj.desc, {skip: cmdObj.skip}, async () => {
165 : 5 : await makeTest(cmdObj);
166 : 5 : });
167 : 5 : }
168 : 1 : });
169 : 1 : }
170 : 1 : }
171 : 1 : /* node:coverage disable */
172 : :
173 : : /**
174 : : * @func defRunner
175 : : * @desc Carry out the loaded tests using this developed test runner.
176 : : */
177 : : function defRunner(){
178 : :
179 : : cmdOptions.verbose && process.on('exit', () => {
180 : : console.log();
181 : : console.log('▶ tests', --testCount);
182 : : console.log('▶ suites', suites.size);
183 : : console.log('▶ pass', passCount);
184 : : console.log('▶ fail', failCount);
185 : : console.log('▶ cancelled', cancelCount);
186 : : console.log('▶ skipped', skipCount);
187 : : console.log('▶ todo', todoCount);
188 : : console.log('▶ duration_ms', Math.round(Date.now() - startTime));
189 : : });
190 : :
191 : : cmdOptions.verbose && console.error();
192 : : for(let [suiteDesc, suiteTests] of suites)
193 : : for(let cmdObj of suiteTests)
194 : : if(!cmdObj.skip){
195 : : (async() => {
196 : : await makeTest(cmdObj);
197 : : })();
198 : : }
199 : :
200 : : cmdOptions.verbose && console.log();
201 : : }
202 : : /* node:coverage enable */
203 : 1 :
204 : 1 : /**
205 : 1 : * @func makeTest
206 : 1 : * async
207 : 1 : * @param {object} obj - The test data object.
208 : 1 : * @desc Carry out a single test.
209 : 1 : */
210 [ + ]: 5 : async function makeTest(obj){
211 : 5 :
212 : 5 : const testID = testCount++;
213 : 5 :
214 : 5 : let preMsg = `Test#${(testID).toString().padStart(3, '0')} ... `;
215 : 5 : let postMsg = preMsg;
216 : 5 :
217 : 5 : preMsg += `Initiate ... ${obj.desc}`;
218 [ - ]: 5 : cmdOptions.verbose && console.error(preMsg);
219 : 5 :
220 : 5 : if(!cmdOptions.verbose){
221 : 5 : await obj.method();
222 [ - ]: 5 : } /* node:coverage disable */
223 : : else{
224 : : try{
225 : : await obj.method();
226 : : passCount++;
227 : :
228 : : postMsg += `Success ... ${obj.desc}`;
229 : : cmdOptions.verbose && console.error(postMsg);
230 : : }
231 : : catch(e){
232 : : failCount++;
233 : :
234 : : postMsg += `Failure ... ${obj.desc}`;
235 : : cmdOptions.verbose && console.error(postMsg);
236 : : }
237 : : } /* node:coverage enable */
238 : 5 : }
|