VS Code extension for easier testing 🛠

This extension enables you to
- quickly open the actual and reference output for a test case to the side
- re-run the test with the click of a button
- approve the test output (moves output to reference folder and optimizes with oxipng)
This commit is contained in:
Laurenz 2021-02-20 23:41:42 +01:00
parent 05727bfc3a
commit 4ff59baf5e
10 changed files with 222 additions and 5 deletions

15
.gitignore vendored
View File

@ -1,13 +1,18 @@
# General
.vscode .vscode
_things _things
# Tests and benchmarks
tests/png
tests/pdf
tarpaulin-report.html
# Rust
/target /target
bench/target bench/target
**/*.rs.bk **/*.rs.bk
Cargo.lock Cargo.lock
tests/png # Node
tests/pdf node_modules
tests/playground.* package-lock.json
tarpaulin-report.html

View File

@ -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`.

View File

@ -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 `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Test output</title>
<style>
body, html {
width: 100%;
text-align: center;
margin: 0;
padding: 0;
}
img {
width: 80%;
max-height: 40vh;
object-fit: contain;
}
</style>
</head>
<body>
<h1>Output image</h1>
<img src="${pngSrc}"/>
<h1>Reference image</h1>
<img src="${refSrc}"/>
</body>
</html>
`
}
function deactivate() {}
module.exports = { activate, deactivate }

View File

@ -0,0 +1,3 @@
<svg width="13" height="13" viewBox="0 0 13 13" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11.2145 2.00909C11.5192 2.3255 11.8278 2.63605 12.1403 2.94073C12.4567 3.24152 12.0423 2.83101 12.347 3.14742L4.97713 10.5114L1.1083 6.63675L2.36684 5.37823L5.10317 8.11456C6.13051 7.09113 7.15004 6.0755 8.16176 5.06769C9.17348 4.05597 10.1911 3.03644 11.2145 2.00909Z" fill="#EAEAEA"/>
</svg>

After

Width:  |  Height:  |  Size: 400 B

View File

@ -0,0 +1,3 @@
<svg width="13" height="13" viewBox="0 0 13 13" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11.2145 2.00909C11.5192 2.3255 11.8278 2.63605 12.1403 2.94073C12.4567 3.24152 12.0423 2.83101 12.347 3.14742L4.97713 10.5114L1.1083 6.63675L2.36684 5.37823L5.10317 8.11456C6.13051 7.09113 7.15004 6.0755 8.16176 5.06769C9.17348 4.05597 10.1911 3.03644 11.2145 2.00909Z" fill="#5A5A5A"/>
</svg>

After

Width:  |  Height:  |  Size: 400 B

View File

@ -0,0 +1,3 @@
<svg width="13" height="13" viewBox="0 0 13 13" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11 7.71571H6.71571V12H5.28429V7.71571H1V6.28429H5.28429V2H6.71571V6.28429H11V7.71571Z" fill="#EAEAEA"/>
</svg>

After

Width:  |  Height:  |  Size: 217 B

View File

@ -0,0 +1,3 @@
<svg width="13" height="13" viewBox="0 0 13 13" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11 7.71571H6.71571V12H5.28429V7.71571H1V6.28429H5.28429V2H6.71571V6.28429H11V7.71571Z" fill="#5A5A5A"/>
</svg>

After

Width:  |  Height:  |  Size: 217 B

View File

@ -0,0 +1,3 @@
<svg width="13" height="13" viewBox="0 0 13 13" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.90572 2.45595C3.25142 2.75992 2.68212 3.19268 2.19784 3.75425L1 2.55641V5.88717H4.33076L2.98609 4.5425C3.17156 4.31582 3.37764 4.11489 3.60433 3.93972C3.83101 3.7594 4.07316 3.60999 4.33076 3.4915C4.58836 3.36785 4.85626 3.27512 5.13447 3.21329C5.41783 3.14632 5.70634 3.11283 6 3.11283C6.53581 3.11283 7.03812 3.21587 7.50695 3.42195C7.98094 3.62287 8.3931 3.90108 8.74343 4.25657C9.09892 4.6069 9.37712 5.01906 9.57805 5.49304C9.78413 5.96188 9.88717 6.46419 9.88717 7H11C11 6.54147 10.9408 6.0984 10.8223 5.67079C10.7038 5.24317 10.5337 4.84647 10.3122 4.48068C10.0958 4.10974 9.83565 3.77228 9.53168 3.46832C9.22772 3.16435 8.89026 2.90417 8.51932 2.68779C8.15353 2.46625 7.75683 2.29624 7.32921 2.17774C6.9016 2.05925 6.45853 2 6 2C5.25811 2 4.56002 2.15198 3.90572 2.45595ZM6.85781 10.7944C6.5796 10.8563 6.29366 10.8872 6 10.8872C5.46419 10.8872 4.9593 10.7867 4.48532 10.5858C4.01649 10.3797 3.60433 10.1015 3.24884 9.75116C2.89851 9.39567 2.6203 8.98351 2.41422 8.51468C2.21329 8.0407 2.11283 7.53581 2.11283 7H1C1 7.45853 1.05925 7.9016 1.17774 8.32921C1.29624 8.75683 1.46368 9.1561 1.68006 9.52705C1.9016 9.89284 2.16435 10.2277 2.46832 10.5317C2.77228 10.8357 3.10716 11.0984 3.47295 11.3199C3.84389 11.5363 4.24317 11.7038 4.67079 11.8223C5.0984 11.9408 5.54147 12 6 12C6.74189 12 7.43998 11.848 8.09428 11.544C8.74858 11.2401 9.31788 10.8073 9.80216 10.2457L11 11.4436V8.11283H7.66924L9.01391 9.4575C8.82844 9.68418 8.62236 9.88769 8.39567 10.068C8.16898 10.2432 7.92684 10.3926 7.66924 10.5162C7.41164 10.6347 7.14116 10.7275 6.85781 10.7944Z" fill="#EAEAEA"/>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -0,0 +1,3 @@
<svg width="13" height="13" viewBox="0 0 13 13" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.90572 2.45595C3.25142 2.75992 2.68212 3.19268 2.19784 3.75425L1 2.55641V5.88717H4.33076L2.98609 4.5425C3.17156 4.31582 3.37764 4.11489 3.60433 3.93972C3.83101 3.7594 4.07316 3.60999 4.33076 3.4915C4.58836 3.36785 4.85626 3.27512 5.13447 3.21329C5.41783 3.14632 5.70634 3.11283 6 3.11283C6.53581 3.11283 7.03812 3.21587 7.50695 3.42195C7.98094 3.62287 8.3931 3.90108 8.74343 4.25657C9.09892 4.6069 9.37712 5.01906 9.57805 5.49304C9.78413 5.96188 9.88717 6.46419 9.88717 7H11C11 6.54147 10.9408 6.0984 10.8223 5.67079C10.7038 5.24317 10.5337 4.84647 10.3122 4.48068C10.0958 4.10974 9.83565 3.77228 9.53168 3.46832C9.22772 3.16435 8.89026 2.90417 8.51932 2.68779C8.15353 2.46625 7.75683 2.29624 7.32921 2.17774C6.9016 2.05925 6.45853 2 6 2C5.25811 2 4.56002 2.15198 3.90572 2.45595ZM6.85781 10.7944C6.5796 10.8563 6.29366 10.8872 6 10.8872C5.46419 10.8872 4.9593 10.7867 4.48532 10.5858C4.01649 10.3797 3.60433 10.1015 3.24884 9.75116C2.89851 9.39567 2.6203 8.98351 2.41422 8.51468C2.21329 8.0407 2.11283 7.53581 2.11283 7H1C1 7.45853 1.05925 7.9016 1.17774 8.32921C1.29624 8.75683 1.46368 9.1561 1.68006 9.52705C1.9016 9.89284 2.16435 10.2277 2.46832 10.5317C2.77228 10.8357 3.10716 11.0984 3.47295 11.3199C3.84389 11.5363 4.24317 11.7038 4.67079 11.8223C5.0984 11.9408 5.54147 12 6 12C6.74189 12 7.43998 11.848 8.09428 11.544C8.74858 11.2401 9.31788 10.8073 9.80216 10.2457L11 11.4436V8.11283H7.66924L9.01391 9.4575C8.82844 9.68418 8.62236 9.88769 8.39567 10.068C8.16898 10.2432 7.92684 10.3926 7.66924 10.5162C7.41164 10.6347 7.14116 10.7275 6.85781 10.7944Z" fill="#5A5A5A"/>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -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"
}
}