Skip to content

Commit

Permalink
feat: introducing status bar item
Browse files Browse the repository at this point in the history
  • Loading branch information
zxch3n committed May 16, 2022
1 parent ce91117 commit 2ad2440
Show file tree
Hide file tree
Showing 7 changed files with 247 additions and 60 deletions.
2 changes: 2 additions & 0 deletions samples/basic/test/add.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { a } from "../src/a";
import { describe, expect, it } from "vitest";

describe("addition", () => {
Expand All @@ -6,6 +7,7 @@ describe("addition", () => {
console.log("=================");
console.log("Console Output");
expect(1 + 1).toBe(2);
expect(a).toBe(5);
});

it("should failed", async () => {
Expand Down
51 changes: 51 additions & 0 deletions src/StatusBarItem.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import * as vscode from "vscode";
import { Command } from "./command";

export class StatusBarItem extends vscode.Disposable {
public item = vscode.window.createStatusBarItem(
vscode.StatusBarAlignment.Left,
5,
);

constructor() {
super(() => {
this.item.dispose();
});

this.toDefaultMode();
}

toDefaultMode() {
this.item.command = Command.StartWatching;
this.item.text = "$(test-view-icon) Vitest";
this.item.tooltip = "Click to start watch mode";
this.item.show();
}

hide() {
this.item.hide();
}

toWatchMode(
{ passed, failed, skipped }: {
passed: number;
failed: number;
skipped: number;
},
) {
this.item.command = Command.StopWatching;
const total = passed + failed;
this.item.text = `$(eye-watch) ${passed}/${total} passed (${
(passed / total * 100).toFixed(0)
}%, ${skipped} skipped)`;
this.item.tooltip = "Vitest is watching. Click to stop.";
this.item.show();
}

toRunningMode() {
this.item.command = Command.StopWatching;
this.item.text = "$(loading~spin) Vitest is running";
this.item.tooltip = "Click to stop watching";
this.item.show();
}
}
1 change: 1 addition & 0 deletions src/command.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export enum Command {
StartWatching = "vitest.startWatching",
StopWatching = "vitest.stopWatching",
UpdateSnapshot = "vitest.updateSnapshot",
}
68 changes: 54 additions & 14 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import { TestFile, WEAKMAP_TEST_DATA } from "./TestData";
import semver from "semver";
import { TestWatcher } from "./watch";
import { Command } from "./command";
import { StatusBarItem } from "./StatusBarItem";
import { effect } from "@vue/reactivity";

export async function activate(context: vscode.ExtensionContext) {
if (
Expand Down Expand Up @@ -58,20 +60,12 @@ export async function activate(context: vscode.ExtensionContext) {

if (semver.gte(vitestVersion, "0.8.0")) {
// enable run/debug/watch tests only if vitest version >= 0.8.0
let testWatcher: undefined | TestWatcher;
if (vitestCmd) {
testWatcher = TestWatcher.create(ctrl, fileDiscoverer, vitestCmd);
context.subscriptions.push(
testWatcher,
vscode.commands.registerCommand(
Command.StartWatching,
() => {
testWatcher!.watch();
},
),
);
}

let testWatcher: undefined | TestWatcher = registerWatchHandler(
vitestCmd,
ctrl,
fileDiscoverer,
context,
);
registerRunHandler(ctrl, testWatcher);
} else {
// v0.8.0 introduce a breaking change in json format
Expand Down Expand Up @@ -108,6 +102,52 @@ export async function activate(context: vscode.ExtensionContext) {
);
}

let statusBarItem: StatusBarItem;
function registerWatchHandler(
vitestCmd: { cmd: string; args: string[] } | undefined,
ctrl: vscode.TestController,
fileDiscoverer: TestFileDiscoverer,
context: vscode.ExtensionContext,
) {
if (!vitestCmd) {
return;
}

const testWatcher = TestWatcher.create(ctrl, fileDiscoverer, vitestCmd);
statusBarItem = new StatusBarItem();
effect(() => {
if (testWatcher.isRunning.value) {
statusBarItem.toRunningMode();
return;
}

if (testWatcher.isWatching.value) {
statusBarItem.toWatchMode(testWatcher.testStatus.value);
return;
}

statusBarItem.toDefaultMode();
});
context.subscriptions.push(
testWatcher,
statusBarItem,
vscode.commands.registerCommand(
Command.StartWatching,
() => {
testWatcher!.watch();
},
),
vscode.commands.registerCommand(
Command.StopWatching,
() => {
testWatcher!.dispose();
},
),
);

return testWatcher;
}

function registerRunHandler(
ctrl: vscode.TestController,
testWatcher?: TestWatcher,
Expand Down
24 changes: 23 additions & 1 deletion src/pure/watch/client.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import WebSocket from "ws";
import { computed, effect, reactive, ref, shallowRef } from "@vue/reactivity";
import type { ResolvedConfig, WebSocketEvents } from "vitest";
import type { ResolvedConfig, Task, TaskResult, WebSocketEvents } from "vitest";
import { createClient } from "./ws-client";

type WebSocketStatus = "OPEN" | "CONNECTING" | "CLOSED";
Expand Down Expand Up @@ -48,10 +48,32 @@ export function buildWatchClient(
});
});

// load result from first run manually
// otherwise those record will not be recorded to client.state
const loadingPromise = client.waitForConnection().then(async () => {
const files = await client.rpc.getFiles();
const idResultPairs: [string, TaskResult][] = [];
files && travel(files);
function travel(tasks: Task[]) {
for (const task of tasks) {
if (task.type === "test") {
if (task.result) {
idResultPairs.push([task.id, task.result]);
}
} else {
travel(task.tasks);
}
}
}

client.state.updateTasks(idResultPairs);
});

return {
client,
config,
status,
files,
loadingPromise,
};
}
20 changes: 13 additions & 7 deletions src/pure/watch/ws-client.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
// this file is copied from vitest with a few modifications;
// it should be patched back to the original files
import { shallowReactive } from "@vue/reactivity";
import type { BirpcReturn } from "birpc";
import { createBirpc } from "birpc";
import { parse, stringify } from "flatted";
import { resolve } from "path";
// eslint-disable-next-line no-restricted-imports
import type { WebSocketEvents, WebSocketHandlers } from "vitest";
import type {
Expand Down Expand Up @@ -119,7 +121,7 @@ export function createClient(url: string, options: VitestClientOptions = {}) {
ws: shallowReactive(new WebSocketConstructor(url)),
state: new StateManager(),
waitForConnection,
reconnect,
reconnect: () => reconnect(true),
}) as VitestClient;

ctx.state.filesMap = reactive(ctx.state.filesMap);
Expand Down Expand Up @@ -151,22 +153,26 @@ export function createClient(url: string, options: VitestClientOptions = {}) {
},
);

let openPromise: Promise<void>;
let openResolve: () => void;
let openPromise: Promise<void> = new Promise((resolve) => {
openResolve = resolve;
});

function reconnect(reset = false) {
if (reset) {
tries = reconnectTries;
openPromise = new Promise((resolve) => {
openResolve = resolve;
});
}
ctx.ws = shallowReactive(new WebSocketConstructor(url));
registerWS();
}

function registerWS() {
openPromise = new Promise((resolve) => {
ctx.ws.addEventListener("open", () => {
tries = reconnectTries;
resolve();
});
ctx.ws.addEventListener("open", () => {
tries = reconnectTries;
openResolve();
});
ctx.ws.addEventListener("message", (v) => {
onMessage(v.data);
Expand Down
Loading

0 comments on commit 2ad2440

Please sign in to comment.