mirror of
https://github.com/wavetermdev/inshellisense.git
synced 2026-08-05 13:43:30 -07:00
ci: add detailed e2e tests & prebuilt node-pty (#188)
* ci: add detailed e2e tests Signed-off-by: Chapman Pendery <cpendery@vt.edu> * fix: e2e test command Signed-off-by: Chapman Pendery <cpendery@vt.edu> * ci: add link cmd to provide is command Signed-off-by: Chapman Pendery <cpendery@vt.edu> * build: drop node-pty for node-pty prebuilds Signed-off-by: Chapman Pendery <cpendery@vt.edu> * fix: ci issues / zsh config Signed-off-by: Chapman Pendery <cpendery@vt.edu> * ci: drop .only for testing Signed-off-by: Chapman Pendery <cpendery@vt.edu> * ci: add back other vms Signed-off-by: Chapman Pendery <cpendery@vt.edu> * fix: add cursor detection Signed-off-by: Chapman Pendery <cpendery@vt.edu> * test: add under test flag to status tests Signed-off-by: Chapman Pendery <cpendery@vt.edu> * fix: use set shell for status check Signed-off-by: Chapman Pendery <cpendery@vt.edu> --------- Signed-off-by: Chapman Pendery <cpendery@vt.edu>
This commit is contained in:
@@ -9,26 +9,53 @@ jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
os: ["windows-latest", "ubuntu-latest"]
|
||||
version: [16, 18, 20]
|
||||
os: ["macos-latest", "windows-latest", "ubuntu-latest"]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Use Node.js 18.x
|
||||
- name: Use Node.js ${{ matrix.version }}.x
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18.x
|
||||
node-version: ${{ matrix.version }}
|
||||
|
||||
- run: npm ci
|
||||
|
||||
- run: npm run lint
|
||||
|
||||
- name: setup zsh-autosuggestions
|
||||
if: matrix.os != 'windows-latest'
|
||||
- name: setup macOS shells
|
||||
if: matrix.os == 'macos-latest'
|
||||
shell: bash
|
||||
run: |
|
||||
brew install fish
|
||||
brew install zsh
|
||||
|
||||
git clone https://github.com/zsh-users/zsh-autosuggestions ~/.zsh/zsh-autosuggestions
|
||||
echo "source ~/.zsh/zsh-autosuggestions/zsh-autosuggestions.zsh" > ~/.zshrc
|
||||
|
||||
sudo chmod g-w /usr/local/share/zsh /usr/local/share/zsh/site-functions /usr/share/zsh
|
||||
|
||||
- name: setup linux shells
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
shell: bash
|
||||
run: |
|
||||
sudo apt-add-repository ppa:fish-shell/release-3
|
||||
sudo apt-get update
|
||||
sudo apt install fish zsh
|
||||
|
||||
git clone https://github.com/zsh-users/zsh-autosuggestions ~/.zsh/zsh-autosuggestions
|
||||
echo "source ~/.zsh/zsh-autosuggestions/zsh-autosuggestions.zsh" > ~/.zshrc
|
||||
|
||||
sudo chmod -R 755 /usr/share/zsh/vendor-completions
|
||||
sudo chown -R root:root /usr/share/zsh/vendor-completions
|
||||
sudo chmod -R 755 /usr/share/zsh
|
||||
sudo chown -R root:root /usr/share/zsh
|
||||
|
||||
- run: npm test
|
||||
|
||||
- run: npm run build
|
||||
|
||||
- run: npm link
|
||||
|
||||
- run: npm run test:e2e
|
||||
|
||||
+2
-1
@@ -1,3 +1,4 @@
|
||||
node_modules/
|
||||
build/
|
||||
t*.md
|
||||
t*.md
|
||||
.tui-test/
|
||||
Generated
+1609
-221
File diff suppressed because it is too large
Load Diff
+4
-2
@@ -4,7 +4,7 @@
|
||||
"description": "IDE style command line auto complete",
|
||||
"type": "module",
|
||||
"engines": {
|
||||
"node" : ">=16.6.0 <21.0.0"
|
||||
"node": ">=16.6.0 <21.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"inshellisense": "./build/index.js",
|
||||
@@ -20,6 +20,7 @@
|
||||
"build": "tsc",
|
||||
"dev": "node --loader ts-node/esm src/index.ts -V",
|
||||
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
|
||||
"test:e2e": "tui-test",
|
||||
"lint": "eslint src/ --ext .ts,.tsx && prettier src/ --check",
|
||||
"lint:fix": "eslint src/ --ext .ts,.tsx --fix && prettier src/ --write",
|
||||
"debug": "node --inspect --loader ts-node/esm src/index.ts -V",
|
||||
@@ -38,6 +39,8 @@
|
||||
},
|
||||
"homepage": "https://github.com/microsoft/inshellisense#readme",
|
||||
"dependencies": {
|
||||
"@homebridge/node-pty-prebuilt-multiarch": "^0.11.12",
|
||||
"@microsoft/tui-test": "^0.0.1-rc.3",
|
||||
"@withfig/autocomplete": "2.651.0",
|
||||
"ajv": "^8.12.0",
|
||||
"ansi-escapes": "^6.2.0",
|
||||
@@ -45,7 +48,6 @@
|
||||
"chalk": "^5.3.0",
|
||||
"commander": "^11.0.0",
|
||||
"find-process": "^1.4.7",
|
||||
"node-pty": "^1.0.0",
|
||||
"which": "^4.0.0",
|
||||
"wrap-ansi": "^8.1.0",
|
||||
"xterm-headless": "^5.3.0"
|
||||
|
||||
@@ -44,7 +44,7 @@ __is_update_prompt() {
|
||||
if [[ $ISTERM_TESTING == "1" ]]; then
|
||||
__is_prior_prompt="> "
|
||||
fi
|
||||
PS1="%{$(__is_prompt_start)%}$PS1%{$(__is_prompt_end)%}"
|
||||
PS1="%{$(__is_prompt_start)%}$__is_prior_prompt%{$(__is_prompt_end)%}"
|
||||
}
|
||||
|
||||
__is_precmd() {
|
||||
|
||||
+7
-1
@@ -7,7 +7,7 @@ import os from "node:os";
|
||||
import path from "node:path";
|
||||
import url from "node:url";
|
||||
|
||||
import pty, { IPty, IEvent } from "node-pty";
|
||||
import pty, { IPty, IEvent } from "@homebridge/node-pty-prebuilt-multiarch";
|
||||
import { Shell, userZdotdir, zdotdir } from "../utils/shell.js";
|
||||
import { IsTermOscPs, IstermOscPt, IstermPromptStart, IstermPromptEnd } from "../utils/ansi.js";
|
||||
import xterm from "xterm-headless";
|
||||
@@ -80,6 +80,12 @@ export class ISTerm implements IPty {
|
||||
};
|
||||
this.onExit = this.#pty.onExit;
|
||||
}
|
||||
on(event: "data", listener: (data: string) => void): void;
|
||||
on(event: "exit", listener: (exitCode: number, signal?: number | undefined) => void): void;
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
on(_event: unknown, _listener: unknown): void {
|
||||
throw new Error("Method not implemented as deprecated in node-pty.");
|
||||
}
|
||||
|
||||
private _deserializeIsMessage(message: string): string {
|
||||
return message.replaceAll(/\\(\\|x([0-9a-f]{2}))/gi, (_match: string, op: string, hex?: string) => (hex ? String.fromCharCode(parseInt(hex, 16)) : op));
|
||||
|
||||
@@ -0,0 +1,179 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
import { test, expect, Shell } from "@microsoft/tui-test";
|
||||
import os from "node:os";
|
||||
|
||||
const windowsShells = [Shell.Cmd, Shell.Powershell, Shell.WindowsPowershell];
|
||||
const unixShells = [Shell.Bash, Shell.Fish, Shell.Zsh];
|
||||
const shells = os.platform() == "win32" ? windowsShells : unixShells;
|
||||
|
||||
shells.map((activeShell) => {
|
||||
test.describe(`[${activeShell}]`, () => {
|
||||
test.use({ program: { file: "is", args: ["-V", "-T", "-s", activeShell] } });
|
||||
|
||||
test("basic git suggestions", async ({ terminal }) => {
|
||||
await expect(terminal.getByText("> ")).toBeVisible();
|
||||
terminal.write("git ");
|
||||
|
||||
await expect(terminal.getByText("blame")).toBeVisible();
|
||||
await expect(terminal.getByText("archive", { strict: false })).toHaveBgColor("7d56f4");
|
||||
});
|
||||
|
||||
test("cursor up when at top of list", async ({ terminal }) => {
|
||||
await expect(terminal.getByText("> ")).toBeVisible();
|
||||
terminal.write("git ");
|
||||
|
||||
await expect(terminal.getByText("archive", { strict: false })).toHaveBgColor("7d56f4");
|
||||
terminal.keyUp();
|
||||
await expect(terminal.getByText("archive", { strict: false })).toHaveBgColor("7d56f4");
|
||||
});
|
||||
|
||||
test("move cursor backwards to hide suggestions", async ({ terminal }) => {
|
||||
await expect(terminal.getByText("> ")).toBeVisible();
|
||||
terminal.write("git ");
|
||||
|
||||
await expect(terminal.getByText("archive", { strict: false })).toBeVisible();
|
||||
|
||||
terminal.keyLeft();
|
||||
await expect(terminal.getByText("archive", { strict: false })).not.toBeVisible();
|
||||
});
|
||||
|
||||
test("cursor down when at top of list", async ({ terminal }) => {
|
||||
await expect(terminal.getByText("> ")).toBeVisible();
|
||||
terminal.write("git ");
|
||||
|
||||
await expect(terminal.getByText("archive", { strict: false })).toBeVisible();
|
||||
terminal.keyDown(2);
|
||||
|
||||
await expect(terminal.getByText("repository")).toBeVisible();
|
||||
await expect(terminal.getByText("commit")).toHaveBgColor("7d56f4");
|
||||
await expect(terminal.getByText("archive", { strict: false })).not.toHaveBgColor("7d56f4");
|
||||
});
|
||||
|
||||
test("scroll down a full page when at top of list", async ({ terminal }) => {
|
||||
await expect(terminal.getByText("> ")).toBeVisible();
|
||||
terminal.write("git ");
|
||||
|
||||
await expect(terminal.getByText("archive", { strict: false })).toBeVisible();
|
||||
terminal.keyDown(5);
|
||||
|
||||
await expect(terminal.getByText("archive", { strict: false })).not.toBeVisible();
|
||||
await expect(terminal.getByText("add")).toHaveBgColor("7d56f4");
|
||||
});
|
||||
|
||||
// excluding cmd since it doesn't support CWD tracking
|
||||
test.when(activeShell !== Shell.Cmd, "generator results lead suggestions", async ({ terminal }) => {
|
||||
await expect(terminal.getByText("> ")).toBeVisible();
|
||||
terminal.write("ls ");
|
||||
|
||||
await expect(terminal.getByText("📀", { strict: false })).toBeVisible();
|
||||
});
|
||||
|
||||
test("tab completion", async ({ terminal }) => {
|
||||
await expect(terminal.getByText("> ")).toBeVisible();
|
||||
terminal.write("git ");
|
||||
|
||||
await expect(terminal.getByText("archive", { strict: false })).toBeVisible();
|
||||
terminal.write("\t");
|
||||
|
||||
await expect(terminal.getByText("--format")).toBeVisible();
|
||||
});
|
||||
|
||||
test("backspacing after accepting tab completion", async ({ terminal }) => {
|
||||
await expect(terminal.getByText("> ")).toBeVisible();
|
||||
terminal.write("git ");
|
||||
|
||||
await expect(terminal.getByText("archive", { strict: false })).toBeVisible();
|
||||
terminal.write("\t");
|
||||
|
||||
await expect(terminal.getByText("--format")).toBeVisible();
|
||||
terminal.keyBackspace(3);
|
||||
|
||||
await expect(terminal.getByText("archive", { strict: false })).toBeVisible();
|
||||
});
|
||||
|
||||
test("suggestion cursor resets between views", async ({ terminal }) => {
|
||||
await expect(terminal.getByText("> ")).toBeVisible();
|
||||
terminal.write("git ");
|
||||
|
||||
await expect(terminal.getByText("archive", { strict: false })).toBeVisible();
|
||||
terminal.keyDown(2);
|
||||
|
||||
await expect(terminal.getByText("repository")).toBeVisible();
|
||||
await expect(terminal.getByText("commit")).toHaveBgColor("7d56f4");
|
||||
|
||||
terminal.keyBackspace(1);
|
||||
await expect(terminal.getByText("repository")).not.toBeVisible();
|
||||
|
||||
terminal.write(" ");
|
||||
await expect(terminal.getByText("archive", { strict: false })).toHaveBgColor("7d56f4");
|
||||
});
|
||||
|
||||
test("ui on bottom of the screen", async ({ terminal }) => {
|
||||
await expect(terminal.getByText("> ")).toBeVisible();
|
||||
terminal.resize(80, 10);
|
||||
terminal.write("\r".repeat(10));
|
||||
|
||||
terminal.write("git ");
|
||||
await expect(terminal.getByText("archive", { strict: false })).toBeVisible();
|
||||
});
|
||||
|
||||
test("command detection after command execution", async ({ terminal }) => {
|
||||
await expect(terminal.getByText("> ")).toBeVisible();
|
||||
|
||||
terminal.write(`echo "hello"\r`);
|
||||
await expect(terminal.getByText("hello", { strict: false })).toBeVisible();
|
||||
|
||||
terminal.write("git ");
|
||||
await expect(terminal.getByText("archive", { strict: false })).toBeVisible();
|
||||
});
|
||||
|
||||
test("command detection after command execution", async ({ terminal }) => {
|
||||
await expect(terminal.getByText("> ")).toBeVisible();
|
||||
|
||||
terminal.write(`echo "hello"\r`);
|
||||
await expect(terminal.getByText("hello", { strict: false })).toBeVisible();
|
||||
|
||||
terminal.write("git ");
|
||||
await expect(terminal.getByText("archive", { strict: false })).toBeVisible();
|
||||
});
|
||||
|
||||
test("suggestions clear after command execution", async ({ terminal }) => {
|
||||
await expect(terminal.getByText("> ")).toBeVisible();
|
||||
|
||||
terminal.write("git ");
|
||||
await expect(terminal.getByText("archive", { strict: false })).toBeVisible();
|
||||
|
||||
terminal.write("\r");
|
||||
await expect(terminal.getByText("archive", { strict: false })).not.toBeVisible();
|
||||
});
|
||||
|
||||
test("access history when no suggestions exist", async ({ terminal }) => {
|
||||
await expect(terminal.getByText("> ")).toBeVisible();
|
||||
|
||||
terminal.write("clear");
|
||||
await expect(terminal.getByText("clear")).toBeVisible();
|
||||
|
||||
terminal.write("\r");
|
||||
await expect(terminal.getByText("clear")).not.toBeVisible();
|
||||
|
||||
terminal.keyUp();
|
||||
await expect(terminal.getByText("clear")).toBeVisible();
|
||||
});
|
||||
|
||||
test.when([Shell.Zsh, Shell.Powershell].includes(activeShell), "command detection with suggestions", async ({ terminal }) => {
|
||||
await expect(terminal.getByText("> ")).toBeVisible();
|
||||
|
||||
terminal.write(`dotnet add item\r`);
|
||||
await expect(terminal.getByText("dotnet", { strict: false })).toBeVisible();
|
||||
|
||||
terminal.write("clear\r");
|
||||
await expect(terminal.getByText("dotnet", { strict: false })).not.toBeVisible();
|
||||
|
||||
terminal.write("dotnet add ");
|
||||
await expect(terminal.getByText("item")).toBeVisible();
|
||||
await expect(terminal.getByText("package", { strict: false })).toBeVisible();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,31 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
import { test, expect, Shell } from "@microsoft/tui-test";
|
||||
import os from "node:os";
|
||||
|
||||
const shell = os.platform() == "darwin" ? Shell.Zsh : os.platform() == "linux" ? Shell.Bash : Shell.Powershell;
|
||||
|
||||
test.describe("status checks", () => {
|
||||
test.describe("inside inshellisense session", () => {
|
||||
test.use({ program: { file: "is", args: ["-T", "-s", shell] } });
|
||||
|
||||
test("current status", async ({ terminal }) => {
|
||||
await expect(terminal.getByText("> ")).toBeVisible();
|
||||
|
||||
terminal.write("is -c\r");
|
||||
await expect(terminal.getByText("live")).toBeVisible();
|
||||
await expect(terminal.getByText("live")).toHaveFgColor(2);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("outside inshellisense session", () => {
|
||||
test("current status", async ({ terminal }) => {
|
||||
await expect(terminal.getByText("> ")).toBeVisible();
|
||||
|
||||
terminal.write("is -c\r");
|
||||
await expect(terminal.getByText("not found")).toBeVisible();
|
||||
await expect(terminal.getByText("not found")).toHaveFgColor(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,8 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
import { defineConfig } from "@microsoft/tui-test";
|
||||
export default defineConfig({
|
||||
testMatch: "src/tests/ui/**/*.@(spec|test).?(c|m)[jt]s?(x)",
|
||||
retries: 3,
|
||||
});
|
||||
Reference in New Issue
Block a user