Skip to content

Commit

Permalink
Add some typescript tests (#173)
Browse files Browse the repository at this point in the history
So far these more or less duplicate a subset of the tests in
`test_typedoc_analysis` so they don't provide that much added value because
they are still basically integration tests with respect to the typescript
logic. But this is a first step and will allow finer grained typescript tests
in the future.
  • Loading branch information
hoodmane authored Dec 22, 2024
1 parent d2aea4b commit b02a30a
Show file tree
Hide file tree
Showing 4 changed files with 141 additions and 2 deletions.
6 changes: 6 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ jobs:
run: |
python -m pip install --upgrade pip
pip install nox
- name: Test
run: nox -s tests-${{ matrix.python-version }}

Expand Down Expand Up @@ -60,6 +61,11 @@ jobs:
steps:
- uses: actions/[email protected]

- name: Set up Node
uses: actions/setup-node@v4
with:
node-version: 22

- name: Set up Python
uses: actions/[email protected]
with:
Expand Down
33 changes: 31 additions & 2 deletions noxfile.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
from pathlib import Path
from textwrap import dedent

import nox
from nox.sessions import Session

PROJECT_ROOT = Path(__file__).parent


@nox.session(python=["3.10", "3.11", "3.12", "3.13"])
def tests(session: Session) -> None:
Expand All @@ -25,15 +28,41 @@ def tests(session: Session) -> None:
@nox.session(python=["3.12"])
@nox.parametrize("typedoc", ["0.25", "0.26"])
def test_typedoc(session: Session, typedoc: str) -> None:
# Install python dependencies
session.install("-r", "requirements_dev.txt")
venvroot = Path(session.bin).parent
(venvroot / "node_modules").mkdir()
node_modules = (venvroot / "node_modules").resolve()
node_modules.mkdir()
with session.chdir(venvroot):
# Install node dependencies
session.run(
"npm", "i", "--no-save", "[email protected]", f"typedoc@{typedoc}", external=True
"npm",
"i",
"--no-save",
"tsx",
"[email protected]",
f"typedoc@{typedoc}",
external=True,
)
session.run("npx", "tsc", "--version", external=True)
session.run("npx", "typedoc", "--version", external=True)
# Run typescript tests
test_file = (PROJECT_ROOT / "tests/test.ts").resolve()
register_import_hook = PROJECT_ROOT / "sphinx_js/js/registerImportHook.mjs"
ts_tests = Path(venvroot / "ts_tests")
# Write script to a file so that it is easy to rerun without reinstalling dependencies.
ts_tests.write_text(
dedent(
f"""\
#!/bin/sh
TYPEDOC_NODE_MODULES={venvroot} node --import {register_import_hook} --import {node_modules/"tsx/dist/loader.mjs"} --test {test_file}
"""
)
)
ts_tests.chmod(0o777)
session.run(ts_tests, external=True)

# Run Python tests
session.run("pytest", "--junitxml=test-results.xml", "-k", "not js")


Expand Down
1 change: 1 addition & 0 deletions sphinx_js/js/importHooks.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export async function resolve(specifier, context, nextResolve) {
for (const parentURL of [origURL, fallbackURL]) {
context.parentURL = parentURL;
const res = await tryResolve(specifier, context, nextResolve);
context.parentURL = origURL;
if (res) {
return res;
}
Expand Down
103 changes: 103 additions & 0 deletions tests/test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import assert from "node:assert";
import { test, suite, before } from "node:test";
import { run } from "../sphinx_js/js/cli";
import { TopLevelIR, Type } from "../sphinx_js/js/ir";
import { Application } from "typedoc";

function joinType(t: Type): string {
return t.map((x) => (typeof x === "string" ? x : x.name)).join("");
}

function resolveFile(path: string): string {
return import.meta.dirname + "/" + path;
}

suite("types.ts", async () => {
let app: Application;
let results: TopLevelIR[];
let map: Map<string, TopLevelIR>;
before(async () => {
[app, results] = await run([
"--sphinxJsConfig",
resolveFile("sphinxJsConfig.ts"),
"--entryPointStrategy",
"expand",
"--tsconfig",
resolveFile("test_typedoc_analysis/source/tsconfig.json"),
"--basePath",
resolveFile("test_typedoc_analysis/source"),
resolveFile("test_typedoc_analysis/source/types.ts"),
]);
map = new Map(results.map((res) => [res.name, res]));
});
function getObject(name: string): TopLevelIR {
const obj = map.get(name);
assert(obj);
return obj!;
}
suite("basic", async () => {
for (const [obj_name, type_name] of [
["bool", "boolean"],
["num", "number"],
["str", "string"],
["array", "number[]"],
["genericArray", "number[]"],
["tuple", "[string, number]"],
["color", "Color"],
["unk", "unknown"],
["whatever", "any"],
["voidy", "void"],
["undef", "undefined"],
["nully", "null"],
["nev", "never"],
["obj", "object"],
["sym", "symbol"],
]) {
await test(obj_name, () => {
const obj = getObject(obj_name);
assert.strictEqual(obj.kind, "attribute");
assert.strictEqual(joinType(obj.type), type_name);
});
}
});
await test("named_interface", () => {
const obj = getObject("interfacer");
assert.strictEqual(obj.kind, "function");
assert.deepStrictEqual(obj.params[0].type, [
{
name: "Interface",
path: ["./", "types.", "Interface"],
type: "internal",
},
]);
});
await test("interface_readonly_member", () => {
const obj = getObject("Interface");
assert.strictEqual(obj.kind, "interface");
const readOnlyNum = obj.members[0];
assert.strictEqual(readOnlyNum.kind, "attribute");
assert.strictEqual(readOnlyNum.name, "readOnlyNum");
assert.deepStrictEqual(readOnlyNum.type, [
{ name: "number", type: "intrinsic" },
]);
});
await test("array", () => {
const obj = getObject("overload");
assert.strictEqual(obj.kind, "function");
assert.deepStrictEqual(obj.params[0].type, [
{ name: "string", type: "intrinsic" },
"[]",
]);
});
await test("literal_types", () => {
const obj = getObject("certainNumbers");
assert.strictEqual(obj.kind, "attribute");
assert.deepStrictEqual(obj.type, [
{
name: "CertainNumbers",
path: ["./", "types.", "CertainNumbers"],
type: "internal",
},
]);
});
});

0 comments on commit b02a30a

Please sign in to comment.