This commit is contained in:
parent
9686ccabc3
commit
47b5bd601c
10 changed files with 6793 additions and 3 deletions
|
@ -1,4 +1,4 @@
|
||||||
name: "Linting"
|
name: "QS"
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
|
@ -16,3 +16,5 @@ jobs:
|
||||||
uses: "https://git.euph.dev/actions/checkout@v3"
|
uses: "https://git.euph.dev/actions/checkout@v3"
|
||||||
- name: "Prettier"
|
- name: "Prettier"
|
||||||
run: npm_config_yes=true npx prettier src/ types/ --check --log-level=error
|
run: npm_config_yes=true npx prettier src/ types/ --check --log-level=error
|
||||||
|
- name: "Run Tests"
|
||||||
|
run: cd test && npm i --no-fund && npm run test
|
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
.idea
|
||||||
|
.vscode
|
||||||
|
|
||||||
|
test/node_modules
|
||||||
|
test/package-lock.json
|
1
.prettierignore
Normal file
1
.prettierignore
Normal file
|
@ -0,0 +1 @@
|
||||||
|
test/data
|
2
Makefile
2
Makefile
|
@ -1,2 +1,2 @@
|
||||||
lint:
|
lint:
|
||||||
@npx prettier src/ types/ --write
|
@npx prettier src/ types/ test/ --write
|
6602
test/data/ccna1v7mod1-3/data.html
Normal file
6602
test/data/ccna1v7mod1-3/data.html
Normal file
File diff suppressed because it is too large
Load diff
60
test/data/ccna1v7mod1-3/test.json
Normal file
60
test/data/ccna1v7mod1-3/test.json
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
{
|
||||||
|
"name": "CCNA 1 v7 Modules 1 - 3 Basic Network Connectivity and Communications Exam Answers",
|
||||||
|
"file": "data.html",
|
||||||
|
"expected": [
|
||||||
|
{
|
||||||
|
"question": "What is an ISP?",
|
||||||
|
"answers": [
|
||||||
|
"It is an organization that enables individuals and businesses to connect to the Internet."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "What type of network traffic requires QoS?",
|
||||||
|
"answers": ["video conferencing"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "Which interface allows remote management of a Layer 2 switch?",
|
||||||
|
"answers": ["the switch virtual interface"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "How is SSH different from Telnet?",
|
||||||
|
"answers": [
|
||||||
|
"SSH provides security to \nremote sessions by encrypting messages and using user authentication. \nTelnet is considered insecure and sends messages in plaintext."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "What are three characteristics of an SVI? (Choose three.)",
|
||||||
|
"answers": [
|
||||||
|
"It is not associated with any physical interface on a switch.",
|
||||||
|
"It provides a means to remotely manage a switch.",
|
||||||
|
"It is associated with VLAN1 by default."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "Which name is assigned to the transport layer PDU?",
|
||||||
|
"answers": ["segment"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "What process involves placing one PDU inside of another PDU?",
|
||||||
|
"answers": ["encapsulation"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "What is a characteristic of multicast messages?",
|
||||||
|
"answers": ["They are sent to a select group of hosts."]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "Which statement is correct about network protocols?",
|
||||||
|
"answers": [
|
||||||
|
"They define how messages are exchanged between the source and the destination."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "Why would a Layer 2 switch need an IP address?",
|
||||||
|
"answers": ["to enable the switch to be managed remotely"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"question": "Which two devices are intermediary devices? (Choose two)",
|
||||||
|
"answers": ["Router", "Switch"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
32
test/fetch.test.js
Normal file
32
test/fetch.test.js
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
const fs = require('fs');
|
||||||
|
const vm = require('vm');
|
||||||
|
const { JSDOM } = require('jsdom');
|
||||||
|
const { diff } = require('deep-diff');
|
||||||
|
|
||||||
|
const scriptContent = fs.readFileSync('../src/fetch.js', 'utf8');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param testData {string}
|
||||||
|
* @param expectedData {Array<Answer>}
|
||||||
|
* @returns {Promise<Array<Answer>>}
|
||||||
|
*/
|
||||||
|
module.exports = async function executeFetchTest(testData, expectedData) {
|
||||||
|
const sandbox = {
|
||||||
|
window: {},
|
||||||
|
DOMParser: new JSDOM().window.DOMParser,
|
||||||
|
console: console
|
||||||
|
};
|
||||||
|
vm.createContext(sandbox);
|
||||||
|
vm.runInContext(scriptContent, sandbox);
|
||||||
|
const { parseAnswers } = sandbox;
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
parseAnswers({ responseText: testData }, results => {
|
||||||
|
const { diff } = require('deep-diff');
|
||||||
|
const changes = diff({ data: results }, { data: expectedData });
|
||||||
|
if (changes !== undefined) {
|
||||||
|
reject(changes);
|
||||||
|
}
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
7
test/jsconfig.json
Normal file
7
test/jsconfig.json
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"checkJs": true,
|
||||||
|
"module": "commonjs",
|
||||||
|
"target": "es6"
|
||||||
|
}
|
||||||
|
}
|
11
test/package.json
Normal file
11
test/package.json
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"scripts": {
|
||||||
|
"test": "node test.js"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"chalk": "^4",
|
||||||
|
"deep-diff": "^1.0.2",
|
||||||
|
"jsdom": "^24.0.0",
|
||||||
|
"vm": "^0.1.0"
|
||||||
|
}
|
||||||
|
}
|
70
test/test.js
Normal file
70
test/test.js
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const chalk = require('chalk');
|
||||||
|
const executeFetchTest = require('./fetch.test');
|
||||||
|
|
||||||
|
const ERROR_MESSAGE = chalk.red('[Error]');
|
||||||
|
const TEST_MESSAGE = chalk.blue('[Test]');
|
||||||
|
const SUCCESS_MESSAGE = chalk.green('Success:');
|
||||||
|
const FAILED_MESSAGE = chalk.red('Failed:');
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
let fail = 0;
|
||||||
|
const dataDirectory = path.join(__dirname, 'data');
|
||||||
|
const directories = fs.readdirSync(dataDirectory);
|
||||||
|
const promises = directories.map(directory => {
|
||||||
|
const testDataDirectory = path.join(dataDirectory, directory);
|
||||||
|
|
||||||
|
if (!fs.lstatSync(testDataDirectory).isDirectory()) {
|
||||||
|
console.error(
|
||||||
|
ERROR_MESSAGE,
|
||||||
|
'Test data directory is not a directory:',
|
||||||
|
testDataDirectory
|
||||||
|
);
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
const testJSONFilePath = path.join(testDataDirectory, 'test.json');
|
||||||
|
if (!fs.existsSync(testJSONFilePath)) {
|
||||||
|
console.error(
|
||||||
|
ERROR_MESSAGE,
|
||||||
|
'Test config file missing:',
|
||||||
|
testJSONFilePath
|
||||||
|
);
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = fs.readFileSync(testJSONFilePath, 'utf8');
|
||||||
|
try {
|
||||||
|
const jsonData = JSON.parse(data);
|
||||||
|
const testData = fs.readFileSync(
|
||||||
|
path.join(testDataDirectory, jsonData.file),
|
||||||
|
'utf8'
|
||||||
|
);
|
||||||
|
|
||||||
|
return executeFetchTest(testData, jsonData.expected)
|
||||||
|
.then(() => {
|
||||||
|
console.log(TEST_MESSAGE, SUCCESS_MESSAGE, jsonData.name);
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
fail++;
|
||||||
|
console.error(
|
||||||
|
TEST_MESSAGE,
|
||||||
|
FAILED_MESSAGE,
|
||||||
|
jsonData.name,
|
||||||
|
error
|
||||||
|
);
|
||||||
|
});
|
||||||
|
} catch (parseErr) {
|
||||||
|
console.error(ERROR_MESSAGE, 'Parsing test config file:', parseErr);
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
await Promise.all(promises);
|
||||||
|
|
||||||
|
if (fail > 0) {
|
||||||
|
process.exitCode = 1;
|
||||||
|
console.error(`${ERROR_MESSAGE} Failed Tests: ${fail}`);
|
||||||
|
}
|
||||||
|
})();
|
Loading…
Reference in a new issue