diff --git a/.gitignore b/.gitignore index e2f07cd6e..ae7d194bd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,18 @@ +# General .vscode _things +# Tests and benchmarks +tests/png +tests/pdf +tarpaulin-report.html + +# Rust /target bench/target **/*.rs.bk Cargo.lock -tests/png -tests/pdf -tests/playground.* - -tarpaulin-report.html +# Node +node_modules +package-lock.json diff --git a/tools/test-helper/README.md b/tools/test-helper/README.md new file mode 100644 index 000000000..8494edeb0 --- /dev/null +++ b/tools/test-helper/README.md @@ -0,0 +1,9 @@ +# Test helper + +This is a small VS Code extension that helps with managing Typst's test suite. +When installed, three new buttons appear in the +menubar for all `.typ` files in the `tests` folder. + +- Open test output: Opens the output and reference images of a test to the side. +- Refresh test output: Re-runs the test and reloads the preview. +- Approve test output: Copies the output into the reference folder and optimizes it with `oxipng`. diff --git a/tools/test-helper/extension.js b/tools/test-helper/extension.js new file mode 100644 index 000000000..775b2894b --- /dev/null +++ b/tools/test-helper/extension.js @@ -0,0 +1,113 @@ +const vscode = require('vscode') +const cp = require('child_process') + +function activate(context) { + let panel = null + + function refreshPanel() { + const uri = vscode.window.activeTextEditor.document.uri + const { pngPath, refPath } = getPaths(uri) + + if (panel && panel.visible) { + console.log('Refreshing WebView') + const pngSrc = panel.webview.asWebviewUri(pngPath) + const refSrc = panel.webview.asWebviewUri(refPath) + panel.webview.html = '' + panel.webview.html = getWebviewContent(pngSrc, refSrc) + } + } + + const openCmd = vscode.commands.registerCommand("ShortcutMenuBar.openTestOutput", () => { + panel = vscode.window.createWebviewPanel( + 'testOutput', + 'Test output', + vscode.ViewColumn.Beside, + {} + ) + + refreshPanel() + }) + + const refreshCmd = vscode.commands.registerCommand("ShortcutMenuBar.refreshTestOutput", () => { + const uri = vscode.window.activeTextEditor.document.uri + const components = uri.fsPath.split('tests') + const dir = components[0] + const subPath = components[1] + + cp.exec( + `cargo test --manifest-path ${dir}/Cargo.toml --test typeset ${subPath}`, + (err, stdout, stderr) => { + console.log(stdout) + console.log(stderr) + refreshPanel() + } + ) + }) + + const approveCmd = vscode.commands.registerCommand("ShortcutMenuBar.approveTestOutput", () => { + const uri = vscode.window.activeTextEditor.document.uri + const { pngPath, refPath } = getPaths(uri) + + vscode.workspace.fs.copy(pngPath, refPath, { overwrite: true }).then(() => { + console.log('Copied to reference file') + cp.exec(`oxipng -o max -a ${refPath.fsPath}`, (err, stdout, stderr) => { + console.log(stdout) + console.log(stderr) + refreshPanel() + }) + }) + }) + + context.subscriptions.push(openCmd) + context.subscriptions.push(refreshCmd) + context.subscriptions.push(approveCmd) +} + +function getPaths(uri) { + const pngPath = vscode.Uri.file(uri.path + .replace("tests/typ", "tests/png") + .replace(".typ", ".png")) + + const refPath = vscode.Uri.file(uri.path + .replace("tests/typ", "tests/ref") + .replace(".typ", ".png")) + + return { pngPath, refPath } +} + +function getWebviewContent(pngSrc, refSrc) { + return ` + + + + + + Test output + + + +

Output image

+ + +

Reference image

+ + + + ` +} + +function deactivate() {} + +module.exports = { activate, deactivate } diff --git a/tools/test-helper/images/approve-dark.svg b/tools/test-helper/images/approve-dark.svg new file mode 100644 index 000000000..027ea6251 --- /dev/null +++ b/tools/test-helper/images/approve-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/tools/test-helper/images/approve-light.svg b/tools/test-helper/images/approve-light.svg new file mode 100644 index 000000000..288b65df1 --- /dev/null +++ b/tools/test-helper/images/approve-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/tools/test-helper/images/open-dark.svg b/tools/test-helper/images/open-dark.svg new file mode 100644 index 000000000..e8631499b --- /dev/null +++ b/tools/test-helper/images/open-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/tools/test-helper/images/open-light.svg b/tools/test-helper/images/open-light.svg new file mode 100644 index 000000000..1301f7113 --- /dev/null +++ b/tools/test-helper/images/open-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/tools/test-helper/images/refresh-dark.svg b/tools/test-helper/images/refresh-dark.svg new file mode 100644 index 000000000..ccd525704 --- /dev/null +++ b/tools/test-helper/images/refresh-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/tools/test-helper/images/refresh-light.svg b/tools/test-helper/images/refresh-light.svg new file mode 100644 index 000000000..a041c7c6b --- /dev/null +++ b/tools/test-helper/images/refresh-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/tools/test-helper/package.json b/tools/test-helper/package.json new file mode 100644 index 000000000..55065838c --- /dev/null +++ b/tools/test-helper/package.json @@ -0,0 +1,72 @@ +{ + "name": "typst-test-helper", + "displayName": "Typst Test Helper", + "description": "Helps to run, compare and approve Typst tests.", + "version": "0.0.1", + "engines": { + "vscode": "^1.53.0" + }, + "categories": [ + "Other" + ], + "activationEvents": [ + "onCommand:ShortcutMenuBar.openTestOutput", + "onCommand:ShortcutMenuBar.approveTestOutput", + "onCommand:ShortcutMenuBar.refreshTestOutput" + ], + "main": "./extension.js", + "contributes": { + "commands": [ + { + "command": "ShortcutMenuBar.openTestOutput", + "title": "Open test output", + "category": "ShortcutMenuBar", + "icon": { + "light": "images/open-light.svg", + "dark": "images/open-dark.svg" + } + }, + { + "command": "ShortcutMenuBar.refreshTestOutput", + "title": "Refresh test output", + "category": "ShortcutMenuBar", + "icon": { + "light": "images/refresh-light.svg", + "dark": "images/refresh-dark.svg" + } + }, + { + "command": "ShortcutMenuBar.approveTestOutput", + "title": "Approve test output", + "category": "ShortcutMenuBar", + "icon": { + "light": "images/approve-light.svg", + "dark": "images/approve-dark.svg" + } + } + ], + "menus": { + "editor/title": [ + { + "when": "resourceExtname == .typ && resourcePath =~ /.*tests.*/", + "command": "ShortcutMenuBar.openTestOutput", + "group": "navigation@0" + }, + { + "when": "resourceExtname == .typ && resourcePath =~ /.*tests.*/", + "command": "ShortcutMenuBar.refreshTestOutput", + "group": "navigation@2" + }, + { + "when": "resourceExtname == .typ && resourcePath =~ /.*tests.*/", + "command": "ShortcutMenuBar.approveTestOutput", + "group": "navigation@3" + } + ] + } + }, + "devDependencies": { + "@types/vscode": "^1.53.0", + "@types/node": "^12.11.7" + } +}