Run JS Widget

Designing webpages is a stepping stone to creating a fully functional website. You can use the 'Run JS widget' to create simple webpages by writing simple HTML, CSS, and JS.

The Run JS widget is the perfect tool to incorporate client-side development into your course. This is what it looks like:

Edit mode
Edit mode

There are 3 basic tabs to operate this widget: HTML, CSS, and JavaScript.

What do I need to know?

  • Default Active Pane: Ā You may want learners to view a particular tab at first glance. Choose the tab from the drop-down menu. The "Output" tab displays your webpage, so it is recommended as the default active pane.

  • Layout: There are three different layouts to arrange the tabs: 'Default', 'Side-by-side', and 'Show Output below'.

    • Default: One tab is visible at a time.

    • Side-by-side: All visible tabs are shown side by side.

    • Show Output below: The 'Output' tab is shifted below the visible tabs.

  • Hide Panels: You may want to hide a particular tab from the learners. Mark the checkbox to hide the tab.

  • Read Only State: You may want learners not to edit code in a particular tab from the learners. Mark the checkbox to restrict the editing.

  • AutoRun: If selected, any change made to the visible tabs will automatically reflect in the output/webpage. If disabled, it automatically enables "Run on load" option. Learners need to press the "Run" button to view the updated webpage.

  • Show Console: You may want learners to monitor the execution on the console along with the webpage. Mark the checkbox to enable console.

  • Line Numbers: You can choose to hide or include line numbers in all visible tabs through this checkbox.

  • Highlight lines: You can highlight important lines of code in any tab. Open the tab and enter the line ranges. For example:
    1-3
    5
    
    This will highlight lines 1-3 and line 5 of the selected tab.
  • Height: You can specify the size of the output window in pixels.

See an example below.

Basic example

In the above example, we have hidden the CSS tab, and default layout is selected. Changing the JS tab will affect the Output tab as "Auto Run" is enabled.

Can I create challenge?

Yes, you can create HTML or JS exercises. You have the option to give the solution for all three tabs: HTML, CSS, and JavaScript. To create an exercise, mark the "Exercise" checkbox. A new tab, "Exercise" will be created.

To enable the testing feature and create an exercise, mark the "Exercise" checkbox in the Run JS panel. The "Exercise" tab will be created beside the "JavaScript (hidden)" tab. You can also mark the "Solution" checkbox to provide solution to the learners.

Begin creating a challenge
Begin creating a challenge

Here, you can find code for a synchronous test.

Commented below is the corresponding test code for an asynchronous test.

Synchronous testing

The synchronous testing is used to create HTML-based exercises only. Any code written in JavaScript will not be detected by the test.

The following sample code provided in the Exercise tab can be manipulated to obtain text/values from any tag in the HTML output. The given test case checks whether the text in the <p> tag is "Hello World".

var TestResult = function() {
this.succeeded = false;
this.reason = "";
this.input = "";
this.expected_output = ""; // Stores the output you expect
this.actual_output = ""; // Stores the output that is being producd by the user
};
var executeTests = function(
userJsCode,
userCssCode,
userHtmlCode,
userHtmlPage // The HTML code of the user's generated page
) {
var results = [];
const jsdom = require("jsdom");
const { JSDOM } = jsdom; // Used to parse userHtmlPage so that its components can be examined
const dom2 = new JSDOM(userHtmlPage, { runScripts: "dangerously" });
const pTag = dom2.window.document.querySelector("p"); // Obtain the <p> tag from the HTML
const result = new TestResult(); // Creating a new test case
result.expected_output = "Hello World";
result.input = "Html page";
if (!pTag) { // Test case 1
result.actual_output = "null";
result.succeeded = false;
result.reason = "No p tag found";
} else {
const pTagText = pTag ? pTag.textContent : ""; // Obtain <p> tag text
result.actual_output = pTagText;
if (pTagText.trim() != "Hello World") { // Test case 2
result.reason = "Expected output (Hello World in a p tag) did not match";
result.succeeded = false;
} else { // Test case 3
result.succeeded = true;
result.reason = "Found p tag with Hello World";
}
}
results.push(result);
return results;
};
  • The jsdom module parses the HTML output, similar to how browsers do it. This allows access to individual tags within the page. The HTML page generated by the user is present in userHtmlPage, which is passed to a jsdom object for parsing.

  • The evaluation code contains a prebuilt object calledĀ TestResult. For any individual test, a TestResult object must be created (line 23). The attributes of this object will be displayed in the final test results, so make sure to fill them appropriately.

The sample exercise is created below.

The CSS and JS tabs are hidden, as they are not relevant to this exercise. To solve the challenge, learners will code in the HTML tab which is set as the default active pane.

Asynchronous testing

Unlike sync tests, the asynchronous testing allows creating async tests that can work with JavaScript. It tests the output page by evaluating the elements from the JavaScript tab. The given test case checks whether the text in the <p> tag is "Hello World".

In the sample test code, comment out the synchronous test and uncomment the part under // Async Tests Example.

var executeTestsAsync = function(
userJsCode,
userCssCode,
userHtmlCode,
userHtmlPage
) {
var results = [];
return new Promise(resolve => {
const jsdom = require("jsdom");
const { JSDOM } = jsdom;
const dom2 = new JSDOM(userHtmlPage, { runScripts: "dangerously" });
if (!dom2.window.onModulesLoaded) {
console.log("window.onModulesLoaded not found!");
resolve(results);
}
dom2.window.onModulesLoaded.then(()=>{
const pTag = dom2.window.document.querySelector("p");
const result = new TestResult();
result.expected_output = "Hello World";
result.input = "Html page";
if (!pTag) {
result.actual_output = "null";
result.succeeded = false;
result.reason = "No p tag found";
} else {
const pTagText = pTag ? pTag.textContent : "";
result.actual_output = pTagText;
if (pTagText.trim() != "Hello World") {
result.reason = "Expected output (Hello World in a p tag) did not match";
result.succeeded = false;
} else {
result.succeeded = true;
result.reason = "Found p tag with Hello World";
}
}
results.push(result);
resolve(results);
});
});
};

Notice, test is the same as what we designed for the synchronous testing example. This time, we're enclosing it in a JS promise (line 8). The dom2.window.onModulesLoaded (at line 14) property is used to check whether an output page is rendered. For this to work, you must create the window.onModulesLoaded component and write code within it.

Note, this time to solve the challenge, learners will code in the JavaScript tab which is set as the default active pane.

Can I give hints for a challenge?

When "Exercise" feature is enabled, you can click the "Add Hint" button below the snippet, to add hint(s) to your solution. Here's an example:

Console

As an example, console is also enabled for the above challenge.

Know the limitations

  • Run JS widget does not support server-side implementation. It only offers a front-end interface

  • Docker isn't supported.

  • On the backend, CSS and JS codes are inserted into the HTML directly, and the resulting iframe is displayed.

To understand the full potential of Run JS, have a look at this comprehensive list of use-cases.