-
Notifications
You must be signed in to change notification settings - Fork 62
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add tests for Documentation Live Preview
- Loading branch information
1 parent
ef0f5de
commit 0ab55b9
Showing
8 changed files
with
280 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
// swift-tools-version: 6.1 | ||
// The swift-tools-version declares the minimum version of Swift required to build this package. | ||
|
||
import PackageDescription | ||
|
||
let package = Package( | ||
name: "documentation-live-preview", | ||
products: [ | ||
// Products define the executables and libraries a package produces, making them visible to other packages. | ||
.library( | ||
name: "Library", | ||
targets: ["Library"]), | ||
], | ||
targets: [ | ||
// Targets are the basic building blocks of a package, defining a module or a test suite. | ||
// Targets can depend on other targets in this package and products from dependencies. | ||
.target( | ||
name: "Library"), | ||
] | ||
) |
3 changes: 3 additions & 0 deletions
3
.../test/documentation-live-preview/Sources/Library/Library.docc/GettingStarted.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# Getting Started | ||
|
||
This is the getting started page. |
5 changes: 5 additions & 0 deletions
5
assets/test/documentation-live-preview/Sources/Library/Library.docc/Tutorial.tutorial
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
@Tutorial(time: 30) { | ||
@Intro(title: "Library") { | ||
Library Tutorial | ||
} | ||
} |
5 changes: 5 additions & 0 deletions
5
...ts/test/documentation-live-preview/Sources/Library/Library.docc/TutorialOverview.tutorial
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
@Tutorials(name: "SlothCreator") { | ||
@Intro(title: "Meet Library") { | ||
Library Tutorial Overview | ||
} | ||
} |
16 changes: 16 additions & 0 deletions
16
assets/test/documentation-live-preview/Sources/Library/Library.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
// The Swift Programming Language | ||
// https://docs.swift.org/swift-book | ||
|
||
/// The entry point for this arbitrary library. | ||
/// | ||
/// Used for testing the Documentation Live Preview. | ||
public struct EntryPoint { | ||
/// The name of this EntryPoint | ||
public let name: String | ||
|
||
/// Creates a new EntryPoint | ||
/// - Parameter name: the name of this entry point | ||
public init(name: String) { | ||
self.name = name | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Used to test Live Preview with an unsupported file. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
225 changes: 225 additions & 0 deletions
225
test/integration-tests/documentation/DocumentationLivePreview.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,225 @@ | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This source file is part of the VS Code Swift open source project | ||
// | ||
// Copyright (c) 2024 the VS Code Swift project authors | ||
// Licensed under Apache License v2.0 | ||
// | ||
// See LICENSE.txt for license information | ||
// See CONTRIBUTORS.txt for the list of VS Code Swift project authors | ||
// | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
import * as vscode from "vscode"; | ||
import * as path from "path"; | ||
import contextKeys from "../../../src/contextKeys"; | ||
import { expect } from "chai"; | ||
import { activateExtensionForSuite, folderInRootWorkspace } from "../utilities/testutilities"; | ||
import { waitForNoRunningTasks } from "../../utilities/tasks"; | ||
import { testAssetUri } from "../../fixtures"; | ||
import { FolderContext } from "../../../src/FolderContext"; | ||
import { WorkspaceContext } from "../../../src/WorkspaceContext"; | ||
import { Commands } from "../../../src/commands"; | ||
import { Workbench } from "../../../src/utilities/commands"; | ||
import { | ||
RenderNodeContent, | ||
WebviewContent, | ||
} from "../../../src/documentation/webview/WebviewMessage"; | ||
import { PreviewEditorConstant } from "../../../src/documentation/DocumentationPreviewEditor"; | ||
|
||
suite("Documentation Live Preview", function () { | ||
// Tests are short, but rely on SourceKit-LSP: give 30 seconds for each one | ||
this.timeout(30 * 1000); | ||
|
||
let folderContext: FolderContext; | ||
let workspaceContext: WorkspaceContext; | ||
|
||
activateExtensionForSuite({ | ||
async setup(ctx) { | ||
workspaceContext = ctx; | ||
await waitForNoRunningTasks(); | ||
folderContext = await folderInRootWorkspace("documentation-live-preview", ctx); | ||
await ctx.focusFolder(folderContext); | ||
}, | ||
}); | ||
|
||
setup(function () { | ||
if (!contextKeys.supportsDocumentationLivePreview) { | ||
this.skip(); | ||
} | ||
}); | ||
|
||
teardown(async function () { | ||
await vscode.commands.executeCommand(Workbench.ACTION_CLOSEALLEDITORS); | ||
}); | ||
|
||
test("renders documentation for an opened Swift file", async function () { | ||
const { webviewContent } = await launchLivePreviewEditor(workspaceContext, { | ||
filePath: "Sources/Library/Library.swift", | ||
position: new vscode.Position(0, 0), | ||
}); | ||
expect(renderNodeString(webviewContent)).to.include( | ||
"The entry point for this arbitrary library." | ||
); | ||
}); | ||
|
||
test("renders documentation when moving the cursor within an opened Swift file", async function () { | ||
const { textEditor } = await launchLivePreviewEditor(workspaceContext, { | ||
filePath: "Sources/Library/Library.swift", | ||
position: new vscode.Position(0, 0), | ||
}); | ||
// Move the cursor to the comment above EntryPoint.name | ||
let webviewContent = await moveCursor(workspaceContext, { | ||
textEditor, | ||
position: new vscode.Position(7, 12), | ||
}); | ||
expect(renderNodeString(webviewContent)).to.include("The name of this EntryPoint"); | ||
// Move the cursor to the comment above EntryPoint.init(name:) | ||
webviewContent = await moveCursor(workspaceContext, { | ||
textEditor, | ||
position: new vscode.Position(10, 18), | ||
}); | ||
expect(renderNodeString(webviewContent)).to.include("Creates a new EntryPoint"); | ||
}); | ||
|
||
test("renders documentation when editing an opened Swift file", async function () { | ||
const { textEditor } = await launchLivePreviewEditor(workspaceContext, { | ||
filePath: "Sources/Library/Library.swift", | ||
position: new vscode.Position(0, 0), | ||
}); | ||
// Edit the comment above EntryPoint | ||
const webviewContent = await editDocument(workspaceContext, textEditor, editBuilder => { | ||
editBuilder.replace(new vscode.Selection(3, 29, 3, 38), "absolutely amazing"); | ||
}); | ||
expect(renderNodeString(webviewContent)).to.include( | ||
"The entry point for this absolutely amazing library." | ||
); | ||
}); | ||
|
||
test("renders documentation for an opened Markdown article", async function () { | ||
const { webviewContent } = await launchLivePreviewEditor(workspaceContext, { | ||
filePath: "Sources/Library/Library.docc/GettingStarted.md", | ||
position: new vscode.Position(0, 0), | ||
}); | ||
expect(renderNodeString(webviewContent)).to.include("This is the getting started page."); | ||
}); | ||
|
||
test("renders documentation for an opened tutorial overview", async function () { | ||
const { webviewContent } = await launchLivePreviewEditor(workspaceContext, { | ||
filePath: "Sources/Library/Library.docc/TutorialOverview.tutorial", | ||
position: new vscode.Position(0, 0), | ||
}); | ||
expect(renderNodeString(webviewContent)).to.include("Library Tutorial Overview"); | ||
}); | ||
|
||
test("renders documentation for an opened tutorial", async function () { | ||
const { webviewContent } = await launchLivePreviewEditor(workspaceContext, { | ||
filePath: "Sources/Library/Library.docc/Tutorial.tutorial", | ||
position: new vscode.Position(0, 0), | ||
}); | ||
expect(renderNodeString(webviewContent)).to.include("Library Tutorial"); | ||
}); | ||
|
||
test("displays an error for an unsupported active document", async function () { | ||
const { webviewContent } = await launchLivePreviewEditor(workspaceContext, { | ||
filePath: "UnsupportedFile.txt", | ||
position: new vscode.Position(0, 0), | ||
}); | ||
expect(webviewContent).to.have.property("type").that.equals("error"); | ||
expect(webviewContent) | ||
.to.have.property("errorMessage") | ||
.that.equals(PreviewEditorConstant.UNSUPPORTED_EDITOR_ERROR_MESSAGE); | ||
}); | ||
}); | ||
|
||
async function launchLivePreviewEditor( | ||
workspaceContext: WorkspaceContext, | ||
options: { | ||
filePath: string; | ||
position: vscode.Position; | ||
} | ||
): Promise<{ textEditor: vscode.TextEditor; webviewContent: WebviewContent }> { | ||
if (findTab(PreviewEditorConstant.VIEW_TYPE, PreviewEditorConstant.TITLE)) { | ||
throw new Error("The live preview editor cannot be launched twice in a single test"); | ||
} | ||
const contentUpdatePromise = waitForNextContentUpdate(workspaceContext); | ||
const renderedPromise = waitForNextRender(workspaceContext); | ||
// Open up the test file before launching live preview | ||
const fileUri = testAssetUri(path.join("documentation-live-preview", options.filePath)); | ||
const selection = new vscode.Selection(options.position, options.position); | ||
const textEditor = await vscode.window.showTextDocument(fileUri, { selection: selection }); | ||
// Launch the documentation preview and wait for it to render | ||
expect(await vscode.commands.executeCommand(Commands.PREVIEW_DOCUMENTATION)).to.be.true; | ||
const [webviewContent] = await Promise.all([contentUpdatePromise, renderedPromise]); | ||
return { textEditor, webviewContent }; | ||
} | ||
|
||
async function editDocument( | ||
workspaceContext: WorkspaceContext, | ||
textEditor: vscode.TextEditor, | ||
callback: (editBuilder: vscode.TextEditorEdit) => void | ||
): Promise<WebviewContent> { | ||
const contentUpdatePromise = waitForNextContentUpdate(workspaceContext); | ||
const renderedPromise = waitForNextRender(workspaceContext); | ||
await expect(textEditor.edit(callback)).to.eventually.be.true; | ||
const [webviewContent] = await Promise.all([contentUpdatePromise, renderedPromise]); | ||
return webviewContent; | ||
} | ||
|
||
async function moveCursor( | ||
workspaceContext: WorkspaceContext, | ||
options: { | ||
textEditor: vscode.TextEditor; | ||
position: vscode.Position; | ||
} | ||
): Promise<WebviewContent> { | ||
const contentUpdatePromise = waitForNextContentUpdate(workspaceContext); | ||
const renderedPromise = waitForNextRender(workspaceContext); | ||
options.textEditor.selection = new vscode.Selection(options.position, options.position); | ||
const [webviewContent] = await Promise.all([contentUpdatePromise, renderedPromise]); | ||
return webviewContent; | ||
} | ||
|
||
function renderNodeString(webviewContent: WebviewContent): string { | ||
expect(webviewContent).to.have.property("type").that.equals("render-node"); | ||
return JSON.stringify((webviewContent as RenderNodeContent).renderNode); | ||
} | ||
|
||
function waitForNextContentUpdate(context: WorkspaceContext): Promise<WebviewContent> { | ||
return new Promise<WebviewContent>(resolve => { | ||
const disposable = context.documentation.onPreviewDidUpdateContent( | ||
(content: WebviewContent) => { | ||
resolve(content); | ||
disposable.dispose(); | ||
} | ||
); | ||
}); | ||
} | ||
|
||
function waitForNextRender(context: WorkspaceContext): Promise<boolean> { | ||
return new Promise<boolean>(resolve => { | ||
const disposable = context.documentation.onPreviewDidRenderContent(() => { | ||
resolve(true); | ||
disposable.dispose(); | ||
}); | ||
}); | ||
} | ||
|
||
function findTab(viewType: string, title: string): vscode.Tab | undefined { | ||
for (const group of vscode.window.tabGroups.all) { | ||
for (const tab of group.tabs) { | ||
// Check if the tab is of type TabInputWebview and matches the viewType and title | ||
if ( | ||
tab.input instanceof vscode.TabInputWebview && | ||
tab.input.viewType.includes(viewType) && | ||
tab.label === title | ||
) { | ||
// We are not checking if tab is active, so return true as long as the if clause is true | ||
return tab; | ||
} | ||
} | ||
} | ||
return undefined; | ||
} |