Skip to content

Initial setup

Ainur Gimadeev edited this page Aug 11, 2022 · 9 revisions

JavaScript

To build a project, we use node. Using node version 12 and above is required. 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 path = require('path');
const pagePath = path.join(__dirname, '../src/index.html');
const {StageTest, correct, wrong} = require('hs-test-web');

class Test extends StageTest {

    page = this.getPage(pagePath)

    tests = [
        this.page.execute(() => {
            // test #1
        }),
        this.page.execute(() => {
            // test #2
        }),
        this.page.execute(() => {
            // test #3
        })
    ]

}

it("Test stage", async () => {
        await new Test().runTests()
    }
).timeout(30000);

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 correct() or 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
this.page.execute(() => {
        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 ?
            correct() :
            wrong(`There should be 7 elements in the body of the HTML document, found: ${len}`)
    }
),
// Test #2
this.page.execute(() => {
    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 ?
        correct() :
        wrong(`Element #${failNum} is not <kbd> element, it's <${failElem}>`);
}),
// Test #3
this.page.execute(() => {
    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 correct();
    }

    if (textInside.length === 0) {
        return wrong(`Element #${failNum} is empty, ` +
            `but should contain a single letter.`);
    }

    return 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": {
    "mocha": "^9.2.0",
    "hs-test-web": "https://github.com/hyperskill/hs-test-web/archive/release.tar.gz",
    "puppeteer": "^13.1.3"
  },
  "scripts": {
    "test": "mocha"
  }
}

Creating project in EduTools

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!

After you finished creating your project, you need to upload it to Stepik. To do this, please click on a project name (the one with 4 squares, not to the one with a book), and click Course Creator -> Upload Hyperskill Lesson to Stepik.

Clone this wiki locally