Skip to content

Commit

Permalink
chore: migrate from jest to mocha
Browse files Browse the repository at this point in the history
Migrates from jest to mocha, tinyspy and c8.
  • Loading branch information
43081j committed Nov 18, 2024
1 parent a80d80b commit ec215ea
Show file tree
Hide file tree
Showing 13 changed files with 1,316 additions and 8,021 deletions.
5 changes: 5 additions & 0 deletions .c8rc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"reporter": ["lcov"],
"include": ["packages/**/*.ts"],
"exclude": ["**/*.test.ts"]
}
6 changes: 3 additions & 3 deletions .github/workflows/nodejs-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,12 @@ jobs:
- run: npm ci
- run: npm run build --if-present

- name: Run Jest
- name: Run unit tests
run: npm run unit-tests
if: matrix.node != env.NODE_COV

- name: Run Jest with coverage
run: npm run unit-tests -- --coverage
- name: Run unit tests with coverage
run: npm run unit-tests-coverage
if: matrix.node == env.NODE_COV

- name: Run Coveralls
Expand Down
7 changes: 7 additions & 0 deletions .mocharc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"require": "ts-node/register",
"loader": "ts-node/esm",
"extensions": ["ts"],
"spec": ["**/*.test.ts"],
"watch-files": ["packages/*/lib"]
}
8 changes: 8 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,14 @@ export default [
'arrow-body-style': ['error', 'as-needed'],
},
},
{
files: testFiles,
languageOptions: {
globals: {
...globals.mocha,
},
},
},
{
files: ['**/*.ts'],
rules: {
Expand Down
9,089 changes: 1,180 additions & 7,909 deletions package-lock.json

Large diffs are not rendered by default.

28 changes: 6 additions & 22 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,18 @@
],
"devDependencies": {
"@eslint/js": "^9.15.0",
"@types/jest": "^29.5.14",
"eslint": "^9.14.0",
"@types/mocha": "^10.0.8",
"c8": "^10.1.2",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-unicorn": "^55.0.0",
"globals": "^15.12.0",
"husky": "^9.1.6",
"jest": "^29.7.0",
"lint-staged": "^15.2.10",
"mocha": "^10.7.3",
"outdent": "^0.8.0",
"prettier": "^3.3.3",
"ts-jest": "^29.2.5",
"tinyspy": "^3.0.2",
"ts-node": "^10.9.2",
"typedoc": "^0.26.11",
"typescript": "^5.6.3",
Expand All @@ -36,7 +37,8 @@
"lint": "npm run lint:es && npm run lint:prettier",
"lint:es": "eslint .",
"lint:prettier": "npm run prettier -- --check",
"unit-tests": "NODE_OPTIONS=--experimental-vm-modules jest",
"unit-tests": "mocha",
"unit-tests-coverage": "c8 mocha",
"test": "npm run lint && npm run unit-tests",
"generate-feedback-tests": "node --loader ts-node/esm scripts/generate-parser-feedback-test/index.ts test/data/html5lib-tests/tree-construction/*.dat",
"bench-perf": "npm run build && node bench/perf/index.js",
Expand All @@ -55,23 +57,5 @@
"*.{md,json,yml}": [
"prettier --write"
]
},
"jest": {
"preset": "ts-jest/presets/default-esm",
"testEnvironment": "node",
"coverageProvider": "v8",
"moduleNameMapper": {
"^(parse5[^/]*)/dist/(.*?)(?:\\.js)?$": "<rootDir>/packages/$1/lib/$2",
"^(parse5[^/]*)$": "<rootDir>/packages/$1/lib/index.ts",
"^(.*)\\.js$": [
"$1",
"$1.js"
]
},
"coveragePathIgnorePatterns": [
"node_modules",
"bench",
"test"
]
}
}
2 changes: 1 addition & 1 deletion packages/parse5-parser-stream/test/location-info.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ generateLocationInfoParserTests('location-info', (input, opts) =>
);

generateTestsForEachTreeAdapter('location-info', (treeAdapter) => {
test('Regression - location info for the implicitly generated <body>, <html> and <head> (GH-44)', () => {
it('Regression - location info for the implicitly generated <body>, <html> and <head> (GH-44)', () => {
const html = '</head><div class="test"></div></body></html>';

const opts = {
Expand Down
4 changes: 2 additions & 2 deletions packages/parse5-parser-stream/test/scripting.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ generateParsingTests(
);

generateTestsForEachTreeAdapter('ParserStream', (treeAdapter) => {
test('Regression - Synchronously calling resume() leads to crash (GH-98)', (done) => {
it('Regression - Synchronously calling resume() leads to crash (GH-98)', (done) => {
const parser = new ParserStream({ treeAdapter });

parser.on('script', (_el, _docWrite, resume) => resume());
Expand All @@ -65,7 +65,7 @@ generateTestsForEachTreeAdapter('ParserStream', (treeAdapter) => {
process.nextTick(done);
});

test('Regression - Parsing loop lock causes accidental hang ups (GH-101)', () => {
it('Regression - Parsing loop lock causes accidental hang ups (GH-101)', () => {
const parser = new ParserStream({ treeAdapter });

parser.on('script', (_scriptElement, _documentWrite, resume) => process.nextTick(resume));
Expand Down
66 changes: 41 additions & 25 deletions packages/parse5/lib/parser/formatting-element-list.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import * as assert from 'node:assert';
import { TAG_NAMES as $, NS, getTagID } from '../common/html.js';
import { type TagToken, TokenType } from '../common/token.js';
import { FormattingElementList, EntryType } from './formatting-element-list.js';
import { type DefaultTreeAdapterMap } from '../tree-adapters/default.js';
import { FormattingElementList, EntryType, type ElementEntry } from './formatting-element-list.js';
import { generateTestsForEachTreeAdapter } from 'parse5-test-utils/utils/common.js';

function createToken(name: $): TagToken {
Expand All @@ -17,7 +18,7 @@ function createToken(name: $): TagToken {
}

generateTestsForEachTreeAdapter('FormattingElementList', (treeAdapter) => {
test('Insert marker', () => {
it('Insert marker', () => {
const list = new FormattingElementList(treeAdapter);

list.insertMarker();
Expand All @@ -29,7 +30,7 @@ generateTestsForEachTreeAdapter('FormattingElementList', (treeAdapter) => {
assert.strictEqual(list.entries[0].type, EntryType.Marker);
});

test('Push element', () => {
it('Push element', () => {
const list = new FormattingElementList(treeAdapter);
const element1Token = createToken($.DIV);
const element2Token = createToken($.P);
Expand All @@ -49,7 +50,7 @@ generateTestsForEachTreeAdapter('FormattingElementList', (treeAdapter) => {
assert.strictEqual(list.entries[0].token, element2Token);
});

test('Insert element after bookmark', () => {
it('Insert element after bookmark', () => {
const list = new FormattingElementList(treeAdapter);
const element1 = treeAdapter.createElement($.DIV, NS.HTML, []);
const element2 = treeAdapter.createElement($.P, NS.HTML, []);
Expand All @@ -65,10 +66,11 @@ generateTestsForEachTreeAdapter('FormattingElementList', (treeAdapter) => {
list.insertElementAfterBookmark(element4, createToken($.TITLE));

assert.strictEqual(list.entries.length, 4);
expect(list.entries[2]).toHaveProperty('element', element4);
assert.ok(Object.prototype.hasOwnProperty.call(list.entries[2], 'element'));
assert.equal((list.entries[2] as ElementEntry<DefaultTreeAdapterMap>).element, element4);
});

test('Push element - Noah Ark condition', () => {
it('Push element - Noah Ark condition', () => {
const list = new FormattingElementList(treeAdapter);
const token1 = createToken($.DIV);
const token2 = createToken($.DIV);
Expand All @@ -93,32 +95,46 @@ generateTestsForEachTreeAdapter('FormattingElementList', (treeAdapter) => {
list.pushElement(element1, token4);

assert.strictEqual(list.entries.length, 4);
expect(list.entries[3]).toHaveProperty('token', token1);
expect(list.entries[2]).toHaveProperty('token', token2);
expect(list.entries[1]).toHaveProperty('token', token3);
expect(list.entries[0]).toHaveProperty('token', token4);
assert.ok(Object.prototype.hasOwnProperty.call(list.entries[3], 'token'));
assert.equal((list.entries[3] as ElementEntry<DefaultTreeAdapterMap>).token, token1);
assert.ok(Object.prototype.hasOwnProperty.call(list.entries[2], 'token'));
assert.equal((list.entries[2] as ElementEntry<DefaultTreeAdapterMap>).token, token2);
assert.ok(Object.prototype.hasOwnProperty.call(list.entries[1], 'token'));
assert.equal((list.entries[1] as ElementEntry<DefaultTreeAdapterMap>).token, token3);
assert.ok(Object.prototype.hasOwnProperty.call(list.entries[0], 'token'));
assert.equal((list.entries[0] as ElementEntry<DefaultTreeAdapterMap>).token, token4);

list.pushElement(element1, token5);

assert.strictEqual(list.entries.length, 4);
expect(list.entries[3]).toHaveProperty('token', token2);
expect(list.entries[2]).toHaveProperty('token', token3);
expect(list.entries[1]).toHaveProperty('token', token4);
expect(list.entries[0]).toHaveProperty('token', token5);
assert.ok(Object.prototype.hasOwnProperty.call(list.entries[3], 'token'));
assert.equal((list.entries[3] as ElementEntry<DefaultTreeAdapterMap>).token, token2);
assert.ok(Object.prototype.hasOwnProperty.call(list.entries[2], 'token'));
assert.equal((list.entries[2] as ElementEntry<DefaultTreeAdapterMap>).token, token3);
assert.ok(Object.prototype.hasOwnProperty.call(list.entries[1], 'token'));
assert.equal((list.entries[1] as ElementEntry<DefaultTreeAdapterMap>).token, token4);
assert.ok(Object.prototype.hasOwnProperty.call(list.entries[0], 'token'));
assert.equal((list.entries[0] as ElementEntry<DefaultTreeAdapterMap>).token, token5);

list.insertMarker();
list.pushElement(element1, token6);

assert.strictEqual(list.entries.length, 6);
expect(list.entries[5]).toHaveProperty('token', token2);
expect(list.entries[4]).toHaveProperty('token', token3);
expect(list.entries[3]).toHaveProperty('token', token4);
expect(list.entries[2]).toHaveProperty('token', token5);
expect(list.entries[1]).toHaveProperty('type', EntryType.Marker);
expect(list.entries[0]).toHaveProperty('token', token6);
assert.ok(Object.prototype.hasOwnProperty.call(list.entries[5], 'token'));
assert.equal((list.entries[5] as ElementEntry<DefaultTreeAdapterMap>).token, token2);
assert.ok(Object.prototype.hasOwnProperty.call(list.entries[4], 'token'));
assert.equal((list.entries[4] as ElementEntry<DefaultTreeAdapterMap>).token, token3);
assert.ok(Object.prototype.hasOwnProperty.call(list.entries[3], 'token'));
assert.equal((list.entries[3] as ElementEntry<DefaultTreeAdapterMap>).token, token4);
assert.ok(Object.prototype.hasOwnProperty.call(list.entries[2], 'token'));
assert.equal((list.entries[2] as ElementEntry<DefaultTreeAdapterMap>).token, token5);
assert.ok(Object.prototype.hasOwnProperty.call(list.entries[1], 'type'));
assert.equal(list.entries[1].type, EntryType.Marker);
assert.ok(Object.prototype.hasOwnProperty.call(list.entries[0], 'token'));
assert.equal((list.entries[0] as ElementEntry<DefaultTreeAdapterMap>).token, token6);
});

test('Clear to the last marker', () => {
it('Clear to the last marker', () => {
const list = new FormattingElementList(treeAdapter);
const token = createToken($.DIV);

Expand Down Expand Up @@ -148,7 +164,7 @@ generateTestsForEachTreeAdapter('FormattingElementList', (treeAdapter) => {
assert.strictEqual(list.entries.length, 0);
});

test('Remove entry', () => {
it('Remove entry', () => {
const list = new FormattingElementList(treeAdapter);
const token = createToken($.DIV);

Expand All @@ -171,11 +187,11 @@ generateTestsForEachTreeAdapter('FormattingElementList', (treeAdapter) => {
assert.strictEqual(list.entries.length, 2);

for (let i = 0; i < list.entries.length; i++) {
expect(list.entries[i]).not.toHaveProperty('element', element1);
assert.notEqual((list.entries[i] as ElementEntry<DefaultTreeAdapterMap>).element, element1);
}
});

test('Get entry in scope with given tag name', () => {
it('Get entry in scope with given tag name', () => {
const list = new FormattingElementList(treeAdapter);
const token = createToken($.DIV);
const element = treeAdapter.createElement($.DIV, NS.HTML, []);
Expand All @@ -193,7 +209,7 @@ generateTestsForEachTreeAdapter('FormattingElementList', (treeAdapter) => {
assert.strictEqual(list.getElementEntryInScopeWithTagName($.DIV), list.entries[0]);
});

test('Get element entry', () => {
it('Get element entry', () => {
const list = new FormattingElementList(treeAdapter);
const token = createToken($.DIV);
const element1 = treeAdapter.createElement($.DIV, NS.HTML, []);
Expand Down
39 changes: 21 additions & 18 deletions packages/parse5/lib/parser/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import * as assert from 'node:assert';
import * as assert from 'node:assert/strict';
import { parseFragment, parse } from 'parse5';
import { jest } from '@jest/globals';
import { generateParsingTests } from 'parse5-test-utils/utils/generate-parsing-tests.js';
import { treeAdapters } from 'parse5-test-utils/utils/common.js';
import type { Element, TextNode } from '../tree-adapters/default.js';
import type { Element, TextNode, DocumentType } from '../tree-adapters/default.js';
import { spy } from 'tinyspy';

generateParsingTests(
'parser',
Expand Down Expand Up @@ -69,24 +69,27 @@ describe('parser', () => {

it('Regression - DOCTYPE empty fields (GH-236)', () => {
const document = parse('<!DOCTYPE>');
const doctype = document.childNodes[0];

expect(doctype).toHaveProperty('name', '');
expect(doctype).toHaveProperty('publicId', '');
expect(doctype).toHaveProperty('systemId', '');
const doctype = document.childNodes[0] as DocumentType;

assert.ok(Object.prototype.hasOwnProperty.call(doctype, 'name'));
assert.equal(doctype.name, '');
assert.ok(Object.prototype.hasOwnProperty.call(doctype, 'publicId'));
assert.equal(doctype.publicId, '');
assert.ok(Object.prototype.hasOwnProperty.call(doctype, 'systemId'));
assert.equal(doctype.systemId, '');
});

it('Regression - CRLF inside </noscript> (GH-710)', () => {
const onParseError = jest.fn();
const onParseError = spy();
parse('<!doctype html><noscript>foo</noscript\r\n>', { onParseError });

expect(onParseError).not.toHaveBeenCalled();
assert.equal(onParseError.called, false);
});

describe('Tree adapters', () => {
it('should support onItemPush and onItemPop', () => {
const onItemPush = jest.fn();
const onItemPop = jest.fn();
const onItemPush = spy();
const onItemPop = spy();
const document = parse('<p><p>', {
treeAdapter: {
...treeAdapters.default,
Expand All @@ -100,15 +103,15 @@ describe('parser', () => {
const bodyElement = htmlElement.childNodes[1];
assert.ok(treeAdapters.default.isElementNode(bodyElement));
// Expect 5 opened elements; in order: html, head, body, and 2x p
expect(onItemPush).toHaveBeenCalledTimes(5);
expect(onItemPush).toHaveBeenNthCalledWith(1, htmlElement);
expect(onItemPush).toHaveBeenNthCalledWith(3, bodyElement);
assert.equal(onItemPush.callCount, 5);
assert.deepEqual(onItemPush.calls[0], [htmlElement]);
assert.deepEqual(onItemPush.calls[2], [bodyElement]);
// The last opened element is the second p
expect(onItemPush).toHaveBeenLastCalledWith(bodyElement.childNodes[1]);
assert.deepEqual(onItemPush.calls[onItemPush.calls.length - 1], [bodyElement.childNodes[1]]);
// The second p isn't closed, plus we never pop body and html. Alas, only 2 pop events (head and p).
expect(onItemPop).toHaveBeenCalledTimes(2);
assert.equal(onItemPop.callCount, 2);
// The last pop event should be the first p.
expect(onItemPop).toHaveBeenLastCalledWith(bodyElement.childNodes[0], bodyElement);
assert.deepEqual(onItemPop.calls[onItemPop.calls.length - 1], [bodyElement.childNodes[0], bodyElement]);
});
});

Expand Down
Loading

0 comments on commit ec215ea

Please sign in to comment.