Skip to content

Tester support for Javascript programming language.#698

Open
Karl-Michaud wants to merge 49 commits intoMarkUsProject:masterfrom
Karl-Michaud:js-autotester
Open

Tester support for Javascript programming language.#698
Karl-Michaud wants to merge 49 commits intoMarkUsProject:masterfrom
Karl-Michaud:js-autotester

Conversation

@Karl-Michaud
Copy link

@Karl-Michaud Karl-Michaud commented Feb 12, 2026

Summary

This PR adds a new JavaScript tester to the autotesting framework, following the structure of the existing testers.

How it works

When tests are run, the tester:

  1. Runs pnpm install in the current working directory to install dependencies from package.json
  2. Runs Jest with --json to get machine-readable output, --forceExit to prevent hanging, and --runInBand to run all tests serially in the current process (important for the shared-resource production environment)
  3. Parses the JSON output and maps each result to the framework's pass/fail/error format
  4. Skips tests with status pending (Jest's term for skipped tests)

Design decisions

  1. pnpm over npm: As indicated in feedback, pnpm is faster and more space-efficient. Node.js, pnpm, and Jest are all installed globally as part of tester installation (e.g.; requirements.system) since they do not need to change on a per-environment basis.

  2. Per-test timeout: Jest's per-test timeout can be configured by instructors via a jest.config.js file. It is not part of the schema.

  3. Test group timeout: A timeout field (default 30s) is included in the schema to set a hard wall-clock limit on the entire Jest run for a test group. This matches how other testers handle group-level timeouts.

  4. Node.js installation: The Debian/Ubuntu package repositories ship outdated versions of Node.js. We use the NodeSource setup script to install Node.js 22, which ensures compatibility with current versions of Jest and JS ecosystem.

  5. Using npm to install Jest and pnpm: In requirements.system, npm is used to install both Jest and pnpm globally. pnpm lacks root privileges during system setup, so pnpm add -g jest fails with a permission error. Two options were considered: (1) npm install -g since npm runs with elevated privileges (chosen); (2) install via curl and manually update the bin path. pnpm is kept for all tester logic where it runs as the user.

  6. create_environment: There is nothing to set up per environment for the JS tester, since pnpm install runs at test time (each student submission may have its own package.json). The function just returns the standard PYTHON env var.

Note: create_environment is called unconditionally by the framework; every tester must have it even if it does nothing.

Karl-Michaud and others added 30 commits February 12, 2026 16:53
Co-Authored-By: lizzie-liu <lizzie-liu@users.noreply.github.com>
Completed `js_tester` logic
Co-Authored-By: freyazjiner <freyazjiner@users.noreply.github.com>
Add requirements.system to install Node.js for JS tester
Use pnpm for JS tester; install pnpm and Jest globally
@Karl-Michaud Karl-Michaud marked this pull request as ready for review March 12, 2026 23:12
@Karl-Michaud Karl-Michaud marked this pull request as draft March 14, 2026 00:57
@Karl-Michaud Karl-Michaud marked this pull request as ready for review March 15, 2026 23:01
README.md Outdated
- `java`
- openjdk-8-jdk
- `js` (JavaScript)
- Node.js
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this isn't exactly right, as "package" here means "system package installed through apt-get"; you can just say "none"

class JsTestData(BaseTestData, kw_only=True):
"""The `test_data` specification for the JavaScript tester."""

timeout: Annotated[int, Meta(title="Test group timeout (seconds)")] = 30
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is necessary as it should already be inherited from BaseTestData

if ! command -v node &> /dev/null; then
apt-get -y update
DEBIAN_FRONTEND=noninteractive apt-get install -y -o 'Dpkg::Options::=--force-confdef' -o 'Dpkg::Options::=--force-confold' curl ca-certificates
curl -fsSL https://deb.nodesource.com/setup_22.x | bash -
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The latest LTS is 24 (not 22), so let's install that

fi

if ! command -v pnpm &> /dev/null; then
npm install -g pnpm
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use corepack to install (https://pnpm.io/installation#using-corepack).

fi

if ! command -v jest &> /dev/null; then
npm install -g jest
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We really should be able to use pnpm to install packages globally. Modify this to use pnpm, and if you still see an error after resolving my other comments, you should do some more debugging. Remember that you can run commands in a test docker container directly (docker compose run --rm server bash); you can also experiment doing so as different users. This script is being run as root.

--runInBand: run all tests serially in the current process
"""
_js_dir = os.path.dirname(os.path.realpath(__file__))
config_path = os.path.join(_js_dir, "jest.config.json")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need to provide a default jest.config.json, this is up to the instructor (or student) to provide.

In the MarkUs repo PR, please include an example jest.config.json file for the autotest scripts and verify that it is being used when running tests.

test_data = self.specs.get("test_data", default={}) or {}

self._ensure_package_json(dir_path)
timeout = test_data.get("timeout", 60)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the default here should be the same as the actual default in the schema (30)

)
return result

def _ensure_package_json(self, dir_path):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function isn't necessary. If a package.json file exists, you can run the pnpm install command, but otherwise just skip it altogether.

You can extend the MarkUs example to actually have two different assignments, one without a package.json file, and one with a package.json file (that actually contains dependencies that are required for the project).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants