Skip to content

Commit 324935b

Browse files
committed
Add tests and test support commands for visual editor
1 parent 0424deb commit 324935b

File tree

6 files changed

+96
-5
lines changed

6 files changed

+96
-5
lines changed

apps/vscode/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
out/
22
*.vsix
33
test-out/
4+
examples-out/

apps/vscode/.vscode-test.mjs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,8 @@ export default defineConfig([
44
{
55
files: 'test-out/*.test.js',
66
workspaceFolder: 'src/test/examples',
7+
mocha: {
8+
timeout: 3000,
9+
},
710
},
811
]);

apps/vscode/src/providers/editor/editor.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ import {
6969
import { ExtensionHost } from "../../host";
7070
import { TabInputCustom } from "vscode";
7171

72+
const kVisualModeConfirmed = "visualModeConfirmed";
73+
7274
export interface QuartoVisualEditor extends QuartoEditor {
7375
hasFocus(): Promise<boolean>;
7476
getActiveBlockContext(): Promise<CodeViewActiveBlockContext | null>;
@@ -87,6 +89,18 @@ export function activateEditor(
8789

8890
// return commands
8991
return [
92+
{
93+
id: 'quarto.test_setkVisualModeConfirmedTrue',
94+
execute() {
95+
context.globalState.update(kVisualModeConfirmed, true);
96+
}
97+
},
98+
{
99+
id: 'quarto.test_isInVisualEditor',
100+
execute() {
101+
return VisualEditorProvider.activeEditor() !== undefined;
102+
}
103+
},
90104
editInVisualModeCommand(),
91105
editInSourceModeCommand(),
92106
toggleEditModeCommand(),
@@ -99,7 +113,7 @@ export class VisualEditorProvider implements CustomTextEditorProvider {
99113

100114
// track the last contents of any active untitled docs (used
101115
// for recovering from attempt to edit )
102-
private static activeUntitled?: { uri: Uri, content: string };
116+
private static activeUntitled?: { uri: Uri, content: string; };
103117

104118
// track the last edited line of code in text editors (used for syncing position)
105119
private static editorLastSourcePos = new Map<string, number>();
@@ -312,7 +326,6 @@ export class VisualEditorProvider implements CustomTextEditorProvider {
312326
private readonly lspRequest: JsonRpcRequestTransport,
313327
private readonly engine: MarkdownEngine) { }
314328

315-
316329
public async resolveCustomTextEditor(
317330
document: TextDocument,
318331
webviewPanel: WebviewPanel,
@@ -333,7 +346,6 @@ export class VisualEditorProvider implements CustomTextEditorProvider {
333346
};
334347

335348
// prompt the user
336-
const kVisualModeConfirmed = "visualModeConfirmed";
337349

338350
// Check for environment variables to force the state of the visual editor confirmation modal
339351
// QUARTO_VISUAL_EDITOR_CONFIRMED > PW_TEST > CI

apps/vscode/src/test/examples/hello.qmd

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,5 @@ format: html
88
```{python}
99
1 + 1
1010
```
11+
12+
*YO!*
Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,56 @@
11
import * as vscode from "vscode";
22
import * as assert from "assert";
3-
import { exampleWorkspacePath } from "./test-utils";
3+
import { exampleWorkspacePath, exampleWorkspaceOutPath, copyFile, wait } from "./test-utils";
44
import { isQuartoDoc } from "../core/doc";
55

6+
const APPROX_TIME_TO_OPEN_VISUAL_EDITOR = 1600;
7+
68
suite("Quarto basics", () => {
9+
// Before we run any tests, we should copy any files that get edited in the tests to file under `exampleWorkspaceOutPath`
10+
suiteSetup(async () => {
11+
const didCopyFile = await copyFile(exampleWorkspacePath('hello.qmd'), exampleWorkspaceOutPath('hello.qmd'));
12+
assert.ok(didCopyFile);
13+
});
14+
715
test("Can open a Quarto document", async () => {
8-
const doc = await vscode.workspace.openTextDocument(exampleWorkspacePath("hello.qmd"));
16+
const doc = await vscode.workspace.openTextDocument(exampleWorkspaceOutPath("hello.qmd"));
917
const editor = await vscode.window.showTextDocument(doc);
18+
1019
assert.strictEqual(editor?.document.languageId, "quarto");
1120
assert.strictEqual(isQuartoDoc(editor?.document), true);
1221
});
22+
// Note: the following tests may be flaky. They rely on waiting estimated amounts of time for commands to complete.
23+
test("Can edit in visual mode", async () => {
24+
const doc = await vscode.workspace.openTextDocument(exampleWorkspaceOutPath("hello.qmd"));
25+
const editor = await vscode.window.showTextDocument(doc);
26+
27+
// manually confirm visual mode so dialogue pop-up doesn't show because dialogues cause test errors
28+
// and switch to visual editor
29+
await vscode.commands.executeCommand("quarto.test_setkVisualModeConfirmedTrue");
30+
await wait(300); // It seems necessary to wait around 300ms for this command to be done.
31+
await vscode.commands.executeCommand("quarto.editInVisualMode");
32+
await wait(APPROX_TIME_TO_OPEN_VISUAL_EDITOR);
33+
34+
assert.ok(await vscode.commands.executeCommand("quarto.test_isInVisualEditor"));
35+
});
36+
// Note: this test runs after the previous test, so `hello.qmd` has already been touched by the previous
37+
// test. That's okay for this test, but could cause issues if you expect a qmd to look how it
38+
// does in `/examples`.
39+
test("Roundtrip doesn't change hello.qmd", async () => {
40+
const doc = await vscode.workspace.openTextDocument(exampleWorkspaceOutPath("hello.qmd"));
41+
const editor = await vscode.window.showTextDocument(doc);
42+
43+
const docTextBefore = doc.getText();
44+
45+
// switch to visual editor and back
46+
await vscode.commands.executeCommand("quarto.test_setkVisualModeConfirmedTrue");
47+
await wait(300);
48+
await vscode.commands.executeCommand("quarto.editInVisualMode");
49+
await wait(APPROX_TIME_TO_OPEN_VISUAL_EDITOR);
50+
await vscode.commands.executeCommand("quarto.editInSourceMode");
51+
await wait(300);
52+
53+
const docTextAfter = doc.getText();
54+
assert.ok(docTextBefore === docTextAfter);
55+
});
1356
});

apps/vscode/src/test/test-utils.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as path from "path";
2+
import * as vscode from "vscode";
23

34

45
/**
@@ -16,3 +17,32 @@ export const WORKSPACE_PATH = path.join(TEST_PATH, "examples");
1617
export function exampleWorkspacePath(file: string): string {
1718
return path.join(WORKSPACE_PATH, file);
1819
}
20+
export function exampleWorkspaceOutPath(file: string): string {
21+
return path.join(WORKSPACE_PATH, 'examples-out', file);
22+
}
23+
24+
export function wait(ms: number) {
25+
return new Promise(resolve => setTimeout(resolve, ms));
26+
}
27+
28+
export async function copyFile(
29+
sourcePath: string,
30+
destPath: string,
31+
): Promise<boolean> {
32+
try {
33+
const wsedit = new vscode.WorkspaceEdit();
34+
const data = await vscode.workspace.fs.readFile(
35+
vscode.Uri.file(sourcePath)
36+
);
37+
const destFileUri = vscode.Uri.file(destPath);
38+
wsedit.createFile(destFileUri, { ignoreIfExists: true });
39+
40+
await vscode.workspace.fs.writeFile(destFileUri, data);
41+
42+
let isDone = await vscode.workspace.applyEdit(wsedit);
43+
if (isDone) return true;
44+
else return false;
45+
} catch (err) {
46+
return false;
47+
}
48+
}

0 commit comments

Comments
 (0)