mirror of
https://github.com/James-Yu/LaTeX-Workshop.git
synced 2025-01-07 09:47:04 +03:00
New test framework
This commit is contained in:
parent
95172d110a
commit
76f59606f6
79
.vscode/launch.json
vendored
79
.vscode/launch.json
vendored
@ -2,23 +2,6 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Launch Node Program",
|
||||
"program": "${file}",
|
||||
"request": "launch",
|
||||
"cwd": "${fileDirname}",
|
||||
"skipFiles": [
|
||||
"<node_internals>/**"
|
||||
],
|
||||
"type": "pwa-node"
|
||||
},
|
||||
{
|
||||
"name": "Python: Current File",
|
||||
"type": "python",
|
||||
"request": "launch",
|
||||
"program": "${file}",
|
||||
"console": "integratedTerminal"
|
||||
},
|
||||
{
|
||||
"name": "Run Extension",
|
||||
"type": "extensionHost",
|
||||
@ -34,72 +17,30 @@
|
||||
"preLaunchTask": "task-watch-all"
|
||||
},
|
||||
{
|
||||
"name": "Run Extension With Sample",
|
||||
"name": "Run Tests",
|
||||
"type": "extensionHost",
|
||||
"request": "launch",
|
||||
"runtimeExecutable": "${execPath}",
|
||||
"args": [
|
||||
"${workspaceFolder}/test/fixtures/testground/",
|
||||
"--extensionDevelopmentPath=${workspaceFolder}",
|
||||
"${workspaceFolder}/samples/sample"
|
||||
"--extensionTestsPath=${workspaceFolder}/out/test/suites/index"
|
||||
],
|
||||
"outFiles": [
|
||||
"${workspaceFolder}/out/src/**/*.js"
|
||||
],
|
||||
"preLaunchTask": "task-watch-all"
|
||||
},
|
||||
{
|
||||
"name": "Run Unit Tests with unittest/fixture001",
|
||||
"type": "extensionHost",
|
||||
"request": "launch",
|
||||
"runtimeExecutable": "${execPath}",
|
||||
"args": [
|
||||
"${workspaceFolder}/test/fixtures/unittest/fixture001",
|
||||
"--extensionDevelopmentPath=${workspaceFolder}",
|
||||
"--extensionTestsPath=${workspaceFolder}/out/test/unittest.index"
|
||||
],
|
||||
"outFiles": [
|
||||
"${workspaceFolder}/out/src/**/*.js",
|
||||
"${workspaceFolder}/out/test/**/*.js"
|
||||
],
|
||||
"preLaunchTask": "task-watch-all"
|
||||
},
|
||||
{
|
||||
"name": "Run Unit Tests with unittest/fixture020",
|
||||
"type": "extensionHost",
|
||||
"request": "launch",
|
||||
"runtimeExecutable": "${execPath}",
|
||||
"args": [
|
||||
"${workspaceFolder}/test/fixtures/unittest/fixture020_structure/",
|
||||
"--extensionDevelopmentPath=${workspaceFolder}",
|
||||
"--extensionTestsPath=${workspaceFolder}/out/test/unittest.index"
|
||||
],
|
||||
"outFiles": [
|
||||
"${workspaceFolder}/out/src/**/*.js",
|
||||
"${workspaceFolder}/out/test/**/*.js"
|
||||
],
|
||||
"preLaunchTask": "task-watch-all",
|
||||
"env": {
|
||||
"LATEXWORKSHOP_CI": "1"
|
||||
"LATEXWORKSHOP_CI": "1",
|
||||
"LATEXWORKSHOP_CISUITE": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Run Unit Tests with unittest/fixture030",
|
||||
"type": "extensionHost",
|
||||
"name": "Python: Current File",
|
||||
"type": "python",
|
||||
"request": "launch",
|
||||
"runtimeExecutable": "${execPath}",
|
||||
"args": [
|
||||
"${workspaceFolder}/test/fixtures/unittest/fixture030_linter/",
|
||||
"--extensionDevelopmentPath=${workspaceFolder}",
|
||||
"--extensionTestsPath=${workspaceFolder}/out/test/unittest.index"
|
||||
],
|
||||
"outFiles": [
|
||||
"${workspaceFolder}/out/src/**/*.js",
|
||||
"${workspaceFolder}/out/test/**/*.js"
|
||||
],
|
||||
"preLaunchTask": "task-watch-all",
|
||||
"env": {
|
||||
"LATEXWORKSHOP_CI": "1"
|
||||
}
|
||||
"program": "${file}",
|
||||
"console": "integratedTerminal"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
21
package-lock.json
generated
21
package-lock.json
generated
@ -27,6 +27,7 @@
|
||||
"@types/micromatch": "4.0.2",
|
||||
"@types/mocha": "9.1.1",
|
||||
"@types/node": "16.11.68",
|
||||
"@types/rimraf": "^3.0.2",
|
||||
"@types/tmp": "0.2.3",
|
||||
"@types/vscode": "1.67.0",
|
||||
"@types/workerpool": "6.1.0",
|
||||
@ -245,6 +246,16 @@
|
||||
"integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/rimraf": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/rimraf/-/rimraf-3.0.2.tgz",
|
||||
"integrity": "sha512-F3OznnSLAUxFrCEu/L5PY8+ny8DtcFRjx7fZZ9bycvXRi3KPTRS9HOitGZwvPg0juRhXFWIeKX58cnX5YqLohQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/glob": "*",
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/semver": {
|
||||
"version": "7.3.13",
|
||||
"resolved": "https://registry.npmmirror.com/@types/semver/-/semver-7.3.13.tgz",
|
||||
@ -4466,6 +4477,16 @@
|
||||
"integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/rimraf": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/rimraf/-/rimraf-3.0.2.tgz",
|
||||
"integrity": "sha512-F3OznnSLAUxFrCEu/L5PY8+ny8DtcFRjx7fZZ9bycvXRi3KPTRS9HOitGZwvPg0juRhXFWIeKX58cnX5YqLohQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/glob": "*",
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/semver": {
|
||||
"version": "7.3.13",
|
||||
"resolved": "https://registry.npmmirror.com/@types/semver/-/semver-7.3.13.tgz",
|
||||
|
@ -2567,6 +2567,7 @@
|
||||
"@types/micromatch": "4.0.2",
|
||||
"@types/mocha": "9.1.1",
|
||||
"@types/node": "16.11.68",
|
||||
"@types/rimraf": "^3.0.2",
|
||||
"@types/tmp": "0.2.3",
|
||||
"@types/vscode": "1.67.0",
|
||||
"@types/workerpool": "6.1.0",
|
||||
|
0
test/fixtures/testground/.gitkeep
vendored
Normal file
0
test/fixtures/testground/.gitkeep
vendored
Normal file
2
test/fixtures/testground/.vscode/settings.json
vendored
Normal file
2
test/fixtures/testground/.vscode/settings.json
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
{
|
||||
}
|
@ -52,9 +52,41 @@ async function runTestsOnEachFixture(targetName: 'build' | 'rootfile' | 'viewer'
|
||||
clearTimeout(nodejsTimeout)
|
||||
}
|
||||
}
|
||||
async function runTestground() {
|
||||
try {
|
||||
const extensionDevelopmentPath = path.resolve(__dirname, '../../')
|
||||
const extensionTestsPath = path.resolve(__dirname, './suites/index')
|
||||
|
||||
const fixtures = glob.sync('test/fixtures/testground', { cwd: extensionDevelopmentPath })
|
||||
for (const fixture of fixtures) {
|
||||
await runTests({
|
||||
version: '1.71.0',
|
||||
extensionDevelopmentPath,
|
||||
extensionTestsPath,
|
||||
launchArgs: [
|
||||
fixture,
|
||||
'--user-data-dir=' + tmpFile.dirSync({ unsafeCleanup: true }).name,
|
||||
'--extensions-dir=' + tmpFile.dirSync({ unsafeCleanup: true }).name,
|
||||
'--lang=C',
|
||||
'--disable-keytar',
|
||||
'--disable-telemetry',
|
||||
'--disable-gpu'
|
||||
],
|
||||
extensionTestsEnv: {
|
||||
LATEXWORKSHOP_CI: '1'
|
||||
}
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
console.error('Failed to run tests')
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
try {
|
||||
await runTestground()
|
||||
await runTestsOnEachFixture('rootfile')
|
||||
await runTestsOnEachFixture('build')
|
||||
await runTestsOnEachFixture('viewer')
|
||||
|
83
test/suites/01_build.test.ts
Normal file
83
test/suites/01_build.test.ts
Normal file
@ -0,0 +1,83 @@
|
||||
import * as vscode from 'vscode'
|
||||
import * as path from 'path'
|
||||
import * as fs from 'fs'
|
||||
import rimraf from 'rimraf'
|
||||
import * as assert from 'assert'
|
||||
|
||||
import { Extension, activate } from '../../src/main'
|
||||
import { assertBuild, runTest, writeTest } from './utils'
|
||||
|
||||
suite('Build TeX files test suite', () => {
|
||||
|
||||
let extension: Extension | undefined
|
||||
const suiteName = path.basename(__filename).replace('.test.js', '')
|
||||
let testground = path.resolve(__dirname, '../../../test/fixtures/testground')
|
||||
|
||||
suiteSetup(async () => {
|
||||
await vscode.commands.executeCommand('latex-workshop.activate')
|
||||
extension = vscode.extensions.getExtension<ReturnType<typeof activate>>('James-Yu.latex-workshop')?.exports.extension
|
||||
assert.ok(extension)
|
||||
testground = path.resolve(extension.extensionRoot, 'test/fixtures/testground')
|
||||
})
|
||||
|
||||
setup(async () => {
|
||||
await vscode.commands.executeCommand('latex-workshop.activate')
|
||||
})
|
||||
|
||||
teardown(async () => {
|
||||
if (path.basename(testground) === 'testground') {
|
||||
rimraf(testground + '/*', (e) => {if (e) {console.error(e)}})
|
||||
fs.closeSync(fs.openSync(testground + '/.gitkeep', 'a'))
|
||||
}
|
||||
await vscode.commands.executeCommand('workbench.action.closeAllEditors')
|
||||
await vscode.workspace.getConfiguration().update('latex-workshop.latex.tools', undefined)
|
||||
await vscode.workspace.getConfiguration().update('latex-workshop.latex.outDir', undefined)
|
||||
await vscode.workspace.getConfiguration().update('latex-workshop.latex.recipes', undefined)
|
||||
await vscode.workspace.getConfiguration().update('latex-workshop.latex.build.forceRecipeUsage', undefined)
|
||||
await vscode.workspace.getConfiguration().update('latex-workshop.latex.rootFile.doNotPrompt', undefined)
|
||||
await vscode.workspace.getConfiguration().update('latex-workshop.latex.rootFile.useSubFile', undefined)
|
||||
await vscode.workspace.getConfiguration().update('latex-workshop.latex.search.rootFiles.include', undefined)
|
||||
await vscode.workspace.getConfiguration().update('latex-workshop.latex.search.rootFiles.exclude', undefined)
|
||||
})
|
||||
|
||||
function writeMainTeX() {
|
||||
writeTest({fixture: testground, fileName: 'main.tex'}, '\\documentclass{article}', '\\begin{document}', 'abc', '\\end{document}')
|
||||
}
|
||||
|
||||
function writeSubFileTeX() {
|
||||
writeTest({fixture: testground, fileName: 'main.tex'}, '\\documentclass{article}', '\\usepackage{subfiles}', '\\begin{document}', 'main main', '\\subfile{sub/s}', '\\end{document}')
|
||||
writeTest({fixture: testground, fileName: 'sub/s.tex'}, '\\documentclass[../main.tex]{subfiles}', '\\begin{document}', 'sub sub', '\\end{document}')
|
||||
}
|
||||
|
||||
runTest({suiteName, fixtureName: 'testground', testName: 'build'}, async () => {
|
||||
writeMainTeX()
|
||||
await assertBuild({fixture: testground, texFileName: 'main.tex', pdfFileName: 'main.pdf', extension})
|
||||
})
|
||||
|
||||
runTest({suiteName, fixtureName: 'testground', testName: 'build with subfiles'}, async () => {
|
||||
writeSubFileTeX()
|
||||
await assertBuild({fixture: testground, texFileName: 'main.tex', pdfFileName: 'main.pdf', extension})
|
||||
})
|
||||
|
||||
runTest({suiteName, fixtureName: 'testground', testName: 'same placeholders multiple times'}, async () => {
|
||||
const tools = [{name: 'latexmk', command: 'latexmk', args: ['-synctex=1', '-interaction=nonstopmode', '-file-line-error', '-pdf', '%DOC%', '%DOC%', '%DOC%']}]
|
||||
await vscode.workspace.getConfiguration().update('latex-workshop.latex.tools', tools)
|
||||
|
||||
writeMainTeX()
|
||||
await assertBuild({fixture: testground, texFileName: 'main.tex', pdfFileName: 'main.pdf', extension})
|
||||
})
|
||||
|
||||
runTest({suiteName, fixtureName: 'testground', testName: 'auto-detect subfile root 1'}, async () => {
|
||||
await vscode.workspace.getConfiguration().update('latex-workshop.latex.rootFile.doNotPrompt', true)
|
||||
await vscode.workspace.getConfiguration().update('latex-workshop.latex.rootFile.useSubFile', true)
|
||||
writeSubFileTeX()
|
||||
await assertBuild({fixture: testground, texFileName: 'sub/s.tex', pdfFileName: 'sub/s.pdf', extension})
|
||||
})
|
||||
|
||||
runTest({suiteName, fixtureName: 'testground', testName: 'auto-detect subfile root 2'}, async () => {
|
||||
await vscode.workspace.getConfiguration().update('latex-workshop.latex.rootFile.doNotPrompt', true)
|
||||
await vscode.workspace.getConfiguration().update('latex-workshop.latex.rootFile.useSubFile', false)
|
||||
writeSubFileTeX()
|
||||
await assertBuild({fixture: testground, texFileName: 'sub/s.tex', pdfFileName: 'main.pdf', extension})
|
||||
})
|
||||
})
|
36
test/suites/index.ts
Normal file
36
test/suites/index.ts
Normal file
@ -0,0 +1,36 @@
|
||||
import * as path from 'path'
|
||||
import Mocha from 'mocha'
|
||||
import glob from 'glob'
|
||||
|
||||
export function run(): Promise<void> {
|
||||
// Create the mocha test
|
||||
const mocha = new Mocha({
|
||||
ui: 'tdd',
|
||||
color: true
|
||||
})
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
glob('**/**.test.js', { cwd: __dirname }, (error, files) => {
|
||||
if (error) {
|
||||
return reject(error)
|
||||
}
|
||||
|
||||
// Add files to the test suite
|
||||
files.forEach(f => mocha.addFile(path.resolve(__dirname, f)))
|
||||
|
||||
try {
|
||||
// Run the mocha test
|
||||
mocha.run(failures => {
|
||||
if (failures > 0) {
|
||||
reject(new Error(`${failures} tests failed.`))
|
||||
} else {
|
||||
resolve()
|
||||
}
|
||||
})
|
||||
} catch (runError) {
|
||||
console.error(runError)
|
||||
reject(runError)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
127
test/suites/utils.ts
Normal file
127
test/suites/utils.ts
Normal file
@ -0,0 +1,127 @@
|
||||
import * as vscode from 'vscode'
|
||||
import * as path from 'path'
|
||||
import * as fs from 'fs'
|
||||
import * as glob from 'glob'
|
||||
import * as os from 'os'
|
||||
import * as assert from 'assert'
|
||||
import { Extension } from '../../src/main'
|
||||
|
||||
type RunTestOption = {
|
||||
suiteName: string,
|
||||
fixtureName: string,
|
||||
testName: string,
|
||||
timeout?: number,
|
||||
only?: boolean,
|
||||
win32only?: boolean
|
||||
}
|
||||
|
||||
export function runTest(option: RunTestOption, cb: (fixture: string) => unknown) {
|
||||
let fixture: string | undefined
|
||||
if (vscode.workspace.workspaceFile) {
|
||||
fixture = path.dirname(vscode.workspace.workspaceFile.fsPath)
|
||||
} else {
|
||||
fixture = vscode.workspace.workspaceFolders?.[0].uri.fsPath
|
||||
}
|
||||
|
||||
if (fixture === undefined) {
|
||||
return
|
||||
}
|
||||
if (path.basename(fixture) !== option.fixtureName) {
|
||||
return
|
||||
}
|
||||
if (process.env['LATEXWORKSHOP_CISUITE'] && !process.env['LATEXWORKSHOP_CISUITE'].split(',').includes(option.suiteName)) {
|
||||
return
|
||||
}
|
||||
if (option.win32only && os.platform() !== 'win32') {
|
||||
return
|
||||
}
|
||||
|
||||
const testFunction = option.only ? test.only : test
|
||||
|
||||
testFunction(`${option.suiteName}: ${option.testName}`, async () => {
|
||||
try {
|
||||
await cb(fixture || '.')
|
||||
} catch (error) {
|
||||
await log()
|
||||
throw error
|
||||
}
|
||||
}).timeout(option.timeout || 30000)
|
||||
}
|
||||
|
||||
export function sleep(ms: number) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms))
|
||||
}
|
||||
|
||||
async function log() {
|
||||
await vscode.commands.executeCommand('workbench.action.output.toggleOutput')
|
||||
await sleep(500)
|
||||
await vscode.commands.executeCommand('latex-workshop.log')
|
||||
await sleep(500)
|
||||
const logMessage = vscode.window.activeTextEditor?.document.getText()
|
||||
console.log(logMessage)
|
||||
await vscode.commands.executeCommand('latex-workshop.compilerlog')
|
||||
await sleep(500)
|
||||
const compilerLogMessage = vscode.window.activeTextEditor?.document.getText()
|
||||
console.log(compilerLogMessage)
|
||||
}
|
||||
|
||||
type WriteTestOption = {
|
||||
fixture: string,
|
||||
fileName: string
|
||||
}
|
||||
|
||||
export function writeTest(option: WriteTestOption, ...contents: string[]) {
|
||||
fs.mkdirSync(path.resolve(option.fixture, path.dirname(option.fileName)), {recursive: true})
|
||||
fs.writeFileSync(path.resolve(option.fixture, option.fileName), contents.join('\n'))
|
||||
}
|
||||
|
||||
type AssertBuildOption = {
|
||||
fixture: string,
|
||||
texFileName: string,
|
||||
pdfFileName: string,
|
||||
extension?: Extension,
|
||||
build?: () => unknown,
|
||||
edits?: (cb: vscode.TextEditorEdit) => unknown,
|
||||
nobuild?: boolean
|
||||
}
|
||||
|
||||
export async function assertBuild(option: AssertBuildOption) {
|
||||
const texFilePath = vscode.Uri.file(path.join(option.fixture, option.texFileName))
|
||||
const pdfFilePath = path.join(option.fixture, option.pdfFileName)
|
||||
const doc = await vscode.workspace.openTextDocument(texFilePath)
|
||||
const editor = await vscode.window.showTextDocument(doc)
|
||||
await option.extension?.manager.findRoot()
|
||||
await executeBuild(editor, doc, option)
|
||||
|
||||
const files = glob.sync('**/**.pdf', { cwd: option.fixture })
|
||||
assert.strictEqual(files.map(file => path.resolve(option.fixture, file)).join(','), option.pdfFileName === '' ? option.pdfFileName : pdfFilePath)
|
||||
}
|
||||
|
||||
async function executeBuild(editor: vscode.TextEditor, doc: vscode.TextDocument, option: AssertBuildOption) {
|
||||
if (option.edits) {
|
||||
await sleep(500)
|
||||
await editor.edit(option.edits)
|
||||
await sleep(500)
|
||||
await doc.save()
|
||||
if (option.nobuild) {
|
||||
await sleep(3000)
|
||||
} else {
|
||||
await waitBuild(option.extension)
|
||||
}
|
||||
return
|
||||
}
|
||||
if (option.build) {
|
||||
await option.build()
|
||||
return
|
||||
}
|
||||
await vscode.commands.executeCommand('latex-workshop.build')
|
||||
}
|
||||
|
||||
export async function waitBuild(extension?: Extension) {
|
||||
return new Promise<void>((resolve, _) => {
|
||||
const disposable = extension?.eventBus.on('buildfinished', () => {
|
||||
resolve()
|
||||
disposable?.dispose()
|
||||
})
|
||||
})
|
||||
}
|
Loading…
Reference in New Issue
Block a user