-
Notifications
You must be signed in to change notification settings - Fork 10
Initial setup for JavaScript
At the moment, we have a separate repository hs-test-web to test JavaScript web applications. Also, with the additional server located on a separate repository hs-test-web-server, you can test web applications based on React library. Visit this page to learn more about testing React applications.
To build a project, we use node
. Use node
version 12 and above to be sure you won't run into trouble, though versions 11 and below haven't been tested and may work properly. A typical project with several stages with JavaScript tests looks like this:
Webstorm_project_folder
.idea
--Idea internal files--
node_modules
--dependencies--
package.json
Project_name
| stage1
| | src
| | | --user files--
| | test
| | --test files--
| stage2
| | src
| | | --user files--
| | test
| | --test files--
| ...
| stageN
| | src
| | | --user files--
| | test
| | --test files--
As you can see, the project is divided into stages. Each stage does not overlap with other stages in any way. The src
package is intended for the user to write his code to the project. The test
folder is intended for writing tests to the project stage.
So, the initial setup for writing tests for a web project is as follows (let's say you're writing tests for the Tic-Tac-Toe project):
Idea_project
package.json
Tic-Tac-Toe
| stage1
| | src
| | | index.html
| | test
| | test.js
The file index.html
can contain some initial code for the student. He'll see it the first time he opens the project. Usually, this file looks like this for a student when opening a project for the first time:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Hello, World!</title>
</head>
<body>
</body>
</html>
But you will need to implement the project stage in this file. Since you will need to check whether your tests work or not.
Below is an initial example of the test.js
file:
const puppeteer = require('puppeteer');
const path = require('path');
// '..' since we're in the test/ subdirectory; learner is supposed to have src/index.html
const pagePath = 'file://' + path.resolve(__dirname, '../src/index.html');
const hs = require('hs-test-web');
const sleep = (ms) => new Promise(res => setTimeout(res, ms));
async function stageTest() {
const browser = await puppeteer.launch({
headless: false,
defaultViewport: null,
args:['--start-maximized', '--disable-infobar'],
ignoreDefaultArgs: ['--enable-automation']
});
const page = await browser.newPage();
await page.goto(pagePath);
page.on('console', msg => console.log(msg.text()));
await sleep(1000);
let result = await hs.testPage(page,
// Test #1
() => {
// test #1
},
// Test #2
() => {
// test #2
},
// Test #3
() => {
// test #3
},
// ...
);
await browser.close();
return result;
}
jest.setTimeout(30000);
test("Test stage", async () => {
let result = await stageTest();
if (result['type'] === 'wrong') {
fail(result['message']);
}
}
);
As you can see, there is a lot of additional code on top of writing tests. This is a subject for simplification in the future. You need to write tests in separate lambdas inside hs.testPage
method.
The test code is executed inside the browser context, not in the node context, so you cannot use any node functions here despite the fact that IDE shows that you can. Local variables are not shared between tests, but global variables are shared. Every test should return either hs.correct()
or hs.wrong(message)
and message
will be shown to the user after the end of the test. Here's an example of 3 tests of the first stage in the Virtual Piano
project. Notice the global variable this.innerBodyElements
that is visible across all the tests.
// Test #1
() => {
let bodyNodes = Array.from(document.body.childNodes);
this.innerBodyElements = bodyNodes.filter(
e => e.nodeType === Node.ELEMENT_NODE);
let len = this.innerBodyElements.length;
return len === 7 ?
hs.correct() :
hs.wrong(`There should be 7 elements in the body of the HTML document, found: ${len}`)
},
// Test #2
() => {
let failNum = 0;
let failElem = '';
let i = 0;
for (let elem of this.innerBodyElements) {
i++;
elem = elem.nodeName.toLowerCase();
if (elem !== 'kbd') {
failNum = i;
failElem = elem;
break;
}
}
return failNum === 0 ?
hs.correct() :
hs.wrong(`Element #${failNum} is not <kbd> element, it's <${failElem}>`);
},
// Test #3
() => {
let failNum = 0;
let textInside = '';
let i = 0;
for (let elem of this.innerBodyElements) {
i++;
elem = elem.innerHTML;
if (elem.length !== 1) {
failNum = i;
textInside = elem;
break;
}
}
if (failNum === 0) {
return hs.correct();
}
if (textInside.length === 0) {
return hs.wrong(`Element #${failNum} is empty, ` +
`but should contain a single letter.`);
}
return hs.wrong(`Element #${failNum} contains ${textInside.length} symbols, ` +
`but should contain a single letter. The text inside element is:\n"${textInside}"`);
},
Below is package.json
file that you can use that contains minimal dependencies needed for any project.
{
"devDependencies": {
"jest": "^23.6.0",
"@types/jest": "^23.3.12",
"hs-test-web": "https://github.com/hyperskill/hs-test-web/archive/v1.tar.gz",
"puppeteer": "^2.0.0"
},
"scripts": {
"test": "jest"
}
}
You are not limited to using the EduTools plugin when creating tests for a project (you can just create a regular Web Storm project), but with the EduTools plugin, it may be more convenient.
To create a project with the EduTools plugin, you need to download install it from the market. Open Settings -> Plugins -> Marketplace -> EduTools
and install the plugin.
To create a project, you need to click File -> Learn and Teach -> Create New Hyperskill Course
Set the title and click Create
.
This is how your project should look like for now. Please, don't touch .yaml
files - they are internal for the EduTools plugin.
Next, you need to delete lesson1
and package-lock.json
. You should end up with a single file package.json
. Replace the contents of this file with what was given above.
Then, you should create a so-called Framework Lesson
and give it a name like a project name. For this, you need to create a new Lesson
and choose Framework lesson
in the dialog.
Then, you should create a new Task
inside this Framework Lesson
and give it the name stage1
. The task type should be Edu
.
Then remove task.js
and hstest/test.java
, create folders test
, src
create files src/index.html
, and test/test.js
and replace the contents of these files with what was provided above. Notice, that you need to name folder and file appropriately your project theme, don't stick to Tic-Tac-Toe
. This is just an example. You should end up with the following configuration:
To create tests for the second stage, click on Framework Lesson
named Tic-Tac-Toe
and add a new Task
. Name it stage2
. Your result should look like the following:
You created an initial setup and ready to write tests!
- Home
- About
- Initial setup
- Writing tests
- Guidelines for writing tests
- Outcomes of testing
- Generating and checking
- Presentation error
- Checking JSON
- Testing solutions written in different languages
- Creating Hyperskill problems based on hs-test
- Testing Java Swing applications
- Testing Java Spring applications
- Testing Ktor applications