mirror of
https://github.com/kiteco/vscode-plugin.git
synced 2024-08-17 11:50:39 +03:00
Line Decoration for Code Nav (#350)
* update: typescript to latest * add: ts bundling with ts-loader * add: KiteCodeLensProvider skeleton * change: wip codelens -> prototype inline decoration * update: rm vscode devDep in favor of @types/vscode and vscode-test See https://code.visualstudio.com/updates/v1_36#_splitting-vscode-package-into-typesvscode-and-vscodetest * improve: consolidate after block to avoid conflicting styles Long standing vscode bug "Inline decorations can interfere with one another" https://github.com/microsoft/vscode/issues/33852 * remove: post-install since now using @types/vscode * update: webpack and webpack-cli to latest * migrate: to using vscode-test via webpack transpiling * improve: fix various tests and improve dev test experience * improve: use link theme color for inline message * improve: bump kite-api and use getLineDecoration * add: source-map and typescript test support * migrate: expect.js -> chai for assertion style testing * remove: unused deps + update sinon * test: codenav-decoration
This commit is contained in:
parent
70f28ba42f
commit
28f70f2d31
@ -12,7 +12,8 @@
|
||||
"browser": false,
|
||||
"commonjs": true,
|
||||
"es6": true,
|
||||
"node": true
|
||||
"node": true,
|
||||
"mocha": true
|
||||
},
|
||||
"rules": {
|
||||
"max-len": "off",
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -45,3 +45,4 @@ sample.html
|
||||
|
||||
# bundled assets
|
||||
dist
|
||||
out
|
||||
|
13
.travis.yml
13
.travis.yml
@ -1,12 +1,16 @@
|
||||
sudo: false
|
||||
sudo: required
|
||||
|
||||
language: node_js
|
||||
node_js:
|
||||
- 10
|
||||
os:
|
||||
- linux
|
||||
|
||||
before_install:
|
||||
- if [ $TRAVIS_OS_NAME == "linux" ]; then
|
||||
export CXX="g++-4.9" CC="gcc-4.9" DISPLAY=:99.0;
|
||||
sh -e /etc/init.d/xvfb start;
|
||||
export CXX="g++-4.9" CC="gcc-4.9";
|
||||
export DISPLAY=':99.0'
|
||||
/usr/bin/Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &
|
||||
sleep 3;
|
||||
fi
|
||||
- curl --silent -L "https://s3-us-west-1.amazonaws.com/kite-data/tensorflow/libtensorflow-cpu-linux-x86_64-1.9.0.tar.gz" | tar -C $HOME -xz
|
||||
@ -20,4 +24,5 @@ install:
|
||||
|
||||
script:
|
||||
- npm test
|
||||
- LIVE_ENVIRONMENT=1 npm test
|
||||
# json-runner.test.js is disabled since it needs updating
|
||||
# - LIVE_ENVIRONMENT=1 npm test
|
||||
|
8
.vscode/launch.json
vendored
8
.vscode/launch.json
vendored
@ -22,12 +22,16 @@
|
||||
"type": "extensionHost",
|
||||
"request": "launch",
|
||||
"runtimeExecutable": "${execPath}",
|
||||
"args": ["--extensionDevelopmentPath=${workspaceFolder}", "--extensionTestsPath=${workspaceFolder}/test", "--disable-extensions" ],
|
||||
"args": [
|
||||
"--extensionDevelopmentPath=${workspaceFolder}",
|
||||
"--extensionTestsPath=${workspaceFolder}/out/test",
|
||||
"--disable-extensions"
|
||||
],
|
||||
"stopOnEntry": false,
|
||||
"outFiles": [
|
||||
"${workspaceFolder}/out/test/**/*.js"
|
||||
],
|
||||
"preLaunchTask": "npm: compile"
|
||||
"preLaunchTask": "npm: compile-test"
|
||||
}
|
||||
]
|
||||
}
|
4
assets/images/logo-light-blue.svg
Normal file
4
assets/images/logo-light-blue.svg
Normal file
@ -0,0 +1,4 @@
|
||||
<svg width="420" height="532" viewBox="0 0 420 532" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M220.062 224.958L137.857 379.629L315.934 531.686L374.875 303.883L220.062 224.958Z" fill="#5DD8E4"/>
|
||||
<path d="M148.303 0L0 261.897L103.229 350.047L203.611 172.788L386.27 259.828L419.99 129.48L148.303 0Z" fill="#5DD8E4"/>
|
||||
</svg>
|
After Width: | Height: | Size: 336 B |
@ -17,7 +17,7 @@ const config = {
|
||||
target: 'node',
|
||||
|
||||
entry: {
|
||||
extension: path.resolve(__dirname, '..', 'src', 'kite.js'),
|
||||
extension: path.resolve(__dirname, '..', 'src', 'kite.js'),
|
||||
},
|
||||
output: {
|
||||
// the bundle is stored in the 'dist' folder (check package.json)
|
||||
@ -31,8 +31,17 @@ const config = {
|
||||
vscode: 'commonjs vscode', // the vscode-module is created on-the-fly and must be excluded.
|
||||
atom: 'atom' // because kite-installer imports it (has null checks around its usage, though)
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.ts$/,
|
||||
use: 'ts-loader',
|
||||
exclude: /node_modules/,
|
||||
},
|
||||
],
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.js']
|
||||
extensions: ['.ts', '.js']
|
||||
},
|
||||
plugins: [
|
||||
// static asset merging and copying
|
||||
@ -59,4 +68,4 @@ const config = {
|
||||
})
|
||||
]
|
||||
};
|
||||
module.exports = config;
|
||||
module.exports = config;
|
||||
|
72
config/webpack.tests.config.js
Normal file
72
config/webpack.tests.config.js
Normal file
@ -0,0 +1,72 @@
|
||||
'use strict';
|
||||
|
||||
const glob = require('glob');
|
||||
const path = require('path');
|
||||
const nodeExternals = require('webpack-node-externals');
|
||||
const CopyPlugin = require('copy-webpack-plugin');
|
||||
|
||||
const OUT_TEST_DIR = path.resolve(__dirname, '..', 'out', 'test');
|
||||
const TEST_DIR = path.resolve(__dirname, '..', 'test');
|
||||
|
||||
const TestNeedsUpdating = {
|
||||
'autostart.test.js': true,
|
||||
'json-runner.test.js': true,
|
||||
};
|
||||
|
||||
const testEntries = glob
|
||||
.sync('*.test.{js,ts}', { cwd: TEST_DIR })
|
||||
.reduce((obj, filename) => {
|
||||
if (!TestNeedsUpdating[filename]) {
|
||||
const filenameWithoutExt = filename.replace(path.extname(filename), '');
|
||||
obj[filenameWithoutExt] = path.resolve(TEST_DIR, filename);
|
||||
}
|
||||
return obj;
|
||||
}, {});
|
||||
|
||||
module.exports = {
|
||||
entry: {
|
||||
['runTests']: path.resolve(__dirname, '..', 'test', 'runTests.js'),
|
||||
['index']: path.resolve(__dirname, '..', 'test', 'index.ts'),
|
||||
...testEntries
|
||||
},
|
||||
output: {
|
||||
path: OUT_TEST_DIR,
|
||||
filename: '[name].js',
|
||||
libraryTarget: 'commonjs2',
|
||||
devtoolModuleFilenameTemplate: '../[resource-path]'
|
||||
},
|
||||
devtool: 'source-map',
|
||||
target: 'node',
|
||||
externals: [
|
||||
{
|
||||
vscode: 'commonjs2 vscode',
|
||||
fs: 'commonjs2 fs',
|
||||
crypto: 'commonjs2 crypto',
|
||||
child_process: 'commonjs2 child_process',
|
||||
['editors-json-tests']: 'commonjs2 editors-json-tests',
|
||||
},
|
||||
nodeExternals()
|
||||
],
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.ts$/,
|
||||
use: 'ts-loader',
|
||||
exclude: /node_modules/,
|
||||
},
|
||||
],
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.ts', '.js'],
|
||||
},
|
||||
plugins: [
|
||||
new CopyPlugin([
|
||||
{
|
||||
from: 'fixtures/',
|
||||
to: path.resolve(OUT_TEST_DIR, 'fixtures/')
|
||||
}
|
||||
],
|
||||
{ context: TEST_DIR }
|
||||
)
|
||||
],
|
||||
};
|
45
package.json
45
package.json
@ -5,7 +5,7 @@
|
||||
"version": "0.135.0",
|
||||
"publisher": "kiteco",
|
||||
"engines": {
|
||||
"vscode": "^1.28.0"
|
||||
"vscode": "^1.32.0"
|
||||
},
|
||||
"icon": "logo.png",
|
||||
"galleryBanner": {
|
||||
@ -345,13 +345,18 @@
|
||||
"type": "array",
|
||||
"default": [],
|
||||
"description": "Array of file extensions for which Kite will not provide completions, e.g. ['.go', '.ts']. Requires restart of VSCode."
|
||||
},
|
||||
"kite.codefinder.enableLineDecoration": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Enables line decoration for Kite code finder."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"postinstall": "node ./node_modules/vscode/bin/install",
|
||||
"test": "node ./node_modules/vscode/bin/test",
|
||||
"compile-test": "rm -rf ./out/test && webpack --config config/webpack.tests.config.js --mode none",
|
||||
"test": "npm run compile-test && node ./out/test/runTests.js",
|
||||
"cleanup": "rm -f package-lock.json && rm -rf node_modules",
|
||||
"vscode:prepublish": "webpack --config config/webpack.config.js --mode production",
|
||||
"compile-prod": "webpack --config config/webpack.config.js --mode production",
|
||||
@ -360,42 +365,44 @@
|
||||
"install-local": "vsce package && code --install-extension kite-*.vsix && rm kite-*.vsix"
|
||||
},
|
||||
"dependencies": {
|
||||
"analytics-node": "^3.1.1",
|
||||
"atob": "^2.1.2",
|
||||
"formidable": "^1.1.1",
|
||||
"getmac": "^1.2.1",
|
||||
"kite-api": "=3.18.0",
|
||||
"kite-api": "=3.19.0",
|
||||
"kite-connector": "=3.12.0",
|
||||
"md5": "^2.2.0",
|
||||
"mixpanel": "^0.5.0",
|
||||
"open": "^7.3.0",
|
||||
"rollbar": "^2.3.8",
|
||||
"tiny-relative-date": "^1.3.0"
|
||||
"rollbar": "^2.3.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@atom/temp": "^0.8.4",
|
||||
"@types/chai": "^4.2.14",
|
||||
"@types/md5": "^2.2.1",
|
||||
"@types/mixpanel": "^2.14.2",
|
||||
"@types/mocha": "^2.2.32",
|
||||
"@types/node": "^6.0.40",
|
||||
"@types/mocha": "^5.2.6",
|
||||
"@types/node": "^10.12.21",
|
||||
"@types/sinon": "^9.0.9",
|
||||
"@types/vscode": "^1.34.0",
|
||||
"@typescript-eslint/eslint-plugin": "^4.7.0",
|
||||
"@typescript-eslint/parser": "^4.7.0",
|
||||
"chai": "^4.2.0",
|
||||
"copy-webpack-plugin": "^5.0.2",
|
||||
"editors-json-tests": "git://github.com/kiteco/editors-json-tests.git#master",
|
||||
"eslint": ">=4.18.2",
|
||||
"expect.js": "^0.3.1",
|
||||
"fs-plus": "^3.0.2",
|
||||
"glob": "^7.1.6",
|
||||
"jsdom": "^10",
|
||||
"jsdom-global": "^3",
|
||||
"mocha": "^5.2.0",
|
||||
"sinon": "^2.3.5",
|
||||
"mocha": "^6.1.4",
|
||||
"sinon": "^9.2.2",
|
||||
"source-map-support": "^0.5.19",
|
||||
"terser": "^3.17.0",
|
||||
"typescript": "^2.0.3",
|
||||
"ts-loader": "^8.0.11",
|
||||
"typescript": "^4.0.5",
|
||||
"vsce": "^1.59.0",
|
||||
"vscode": "^1.1.22",
|
||||
"webpack": "^4.30.0",
|
||||
"webpack-cli": "^3.3.0",
|
||||
"vscode-test": "^1.4.1",
|
||||
"webpack": "^5.10.3",
|
||||
"webpack-cli": "^4.2.0",
|
||||
"webpack-merge-and-include-globally": "^2.1.16",
|
||||
"webpack-node-externals": "^2.5.2",
|
||||
"widjet-test-utils": "^1.8.0"
|
||||
}
|
||||
}
|
||||
|
128
src/codenav-decoration.ts
Normal file
128
src/codenav-decoration.ts
Normal file
@ -0,0 +1,128 @@
|
||||
import * as path from 'path';
|
||||
import {
|
||||
DecorationOptions,
|
||||
DecorationRangeBehavior,
|
||||
Event,
|
||||
extensions,
|
||||
MarkdownString,
|
||||
Position,
|
||||
Range,
|
||||
TextEditor,
|
||||
TextEditorDecorationType,
|
||||
TextEditorSelectionChangeEvent,
|
||||
ThemeColor,
|
||||
window,
|
||||
workspace
|
||||
} from 'vscode';
|
||||
|
||||
import * as KiteAPI from "kite-api";
|
||||
|
||||
const relatedCodeLineDecoration: TextEditorDecorationType = window.createTextEditorDecorationType({
|
||||
rangeBehavior: DecorationRangeBehavior.ClosedOpen,
|
||||
});
|
||||
|
||||
interface decorationStatusResponse {
|
||||
inlineMessage: string,
|
||||
hoverMessage: string,
|
||||
projectReady: boolean,
|
||||
}
|
||||
|
||||
interface IOnDidChangeTextEditorSelection {
|
||||
onDidChangeTextEditorSelection: Event<TextEditorSelectionChangeEvent>
|
||||
}
|
||||
|
||||
export default class KiteRelatedCodeDecorationsProvider {
|
||||
private lineInfo: decorationStatusResponse | undefined
|
||||
private activeEditor: TextEditor | undefined
|
||||
|
||||
constructor(win: IOnDidChangeTextEditorSelection = window) {
|
||||
this.lineInfo = undefined;
|
||||
this.activeEditor = undefined;
|
||||
win.onDidChangeTextEditorSelection(this.onDidChangeTextEditorSelection.bind(this));
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
// Clears all decorations of this type
|
||||
relatedCodeLineDecoration.dispose();
|
||||
}
|
||||
|
||||
// For testing and easy stubbing
|
||||
public enabled(): boolean {
|
||||
return workspace.getConfiguration('kite').codefinder.enableLineDecoration;
|
||||
}
|
||||
|
||||
// Public for testing
|
||||
public async onDidChangeTextEditorSelection(event: TextEditorSelectionChangeEvent): Promise<void> {
|
||||
if (!this.enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const editor = event.textEditor;
|
||||
const applicable = this.lineInfo && this.lineInfo.projectReady !== undefined;
|
||||
const ready = this.lineInfo && this.lineInfo.projectReady;
|
||||
if (!this.lineInfo || editor !== this.activeEditor || (applicable && !ready)) {
|
||||
await this.reset(editor);
|
||||
} else if (event.selections.length != 1) {
|
||||
await this.reset(editor);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.lineInfo && this.lineInfo.projectReady) {
|
||||
const cursor: Position = event.selections[0].active;
|
||||
const opts: DecorationOptions = {
|
||||
hoverMessage: this.hoverMessage(this.lineInfo.hoverMessage),
|
||||
range: this.lineEnd(cursor),
|
||||
renderOptions: {
|
||||
after: {
|
||||
contentText: `${this.lineInfo.inlineMessage}`,
|
||||
margin: '0 0 0 3em',
|
||||
color: new ThemeColor('textLink.activeForeground'),
|
||||
fontWeight: 'normal',
|
||||
fontStyle: 'normal',
|
||||
}
|
||||
}
|
||||
};
|
||||
editor.setDecorations(relatedCodeLineDecoration, [opts]);
|
||||
}
|
||||
}
|
||||
|
||||
private hoverMessage(hover: string): MarkdownString {
|
||||
const logo = path.join(extensions.getExtension("kiteco.kite").extensionPath , "/dist/assets/images/logo-light-blue.svg");
|
||||
const md = new MarkdownString(`![KiteIcon](${logo}|height=10) [${hover}](command:kite.related-code-from-line)`);
|
||||
// Must mark as trusted to run commands in MarkdownStrings
|
||||
md.isTrusted = true;
|
||||
return md;
|
||||
}
|
||||
|
||||
private lineEnd(pos: Position): Range {
|
||||
const ending = pos.with(pos.line, 9999);
|
||||
return new Range(ending, ending);
|
||||
}
|
||||
|
||||
private async reset(editor: TextEditor): Promise<void> {
|
||||
editor.setDecorations(relatedCodeLineDecoration, []);
|
||||
this.activeEditor = editor;
|
||||
this.lineInfo = undefined;
|
||||
const info = await this.fetchDecoration(editor.document.fileName);
|
||||
if (!info) {
|
||||
return;
|
||||
}
|
||||
this.lineInfo = info;
|
||||
}
|
||||
|
||||
private async fetchDecoration(filename: string): Promise<decorationStatusResponse | null> {
|
||||
try {
|
||||
const resp = await KiteAPI.getLineDecoration(filename);
|
||||
if (resp && !resp.err) {
|
||||
return {
|
||||
inlineMessage: resp.inline_message,
|
||||
hoverMessage: resp.hover_message,
|
||||
projectReady: resp.project_ready,
|
||||
} as decorationStatusResponse;
|
||||
}
|
||||
} catch (e) {
|
||||
// pass
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -130,11 +130,11 @@ const processCompletion = (
|
||||
};
|
||||
|
||||
export default class KiteCompletionProvider {
|
||||
constructor(Kite, triggers, optionalTriggers, isTest) {
|
||||
constructor(Kite, triggers, optionalTriggers, win = window) {
|
||||
this.Kite = Kite;
|
||||
this.triggers = triggers;
|
||||
this.optionalTriggers = optionalTriggers || [];
|
||||
this.isTest = isTest;
|
||||
this.window = win;
|
||||
}
|
||||
|
||||
provideCompletionItems(document, position, token, context) {
|
||||
@ -151,7 +151,7 @@ export default class KiteCompletionProvider {
|
||||
}
|
||||
|
||||
getCompletions(document, text, filename, filterText, context) {
|
||||
const selection = window.activeTextEditor.selection;
|
||||
const selection = this.window.activeTextEditor.selection;
|
||||
const begin = document.offsetAt(selection.start);
|
||||
const end = document.offsetAt(selection.end);
|
||||
const enableSnippets = workspace.getConfiguration("kite").enableSnippets;
|
||||
|
@ -34,6 +34,7 @@ import {
|
||||
} from "./utils";
|
||||
import { version } from "../package.json";
|
||||
import { DEFAULT_MAX_FILE_SIZE } from "kite-api";
|
||||
import KiteRelatedCodeDecorationsProvider from './codenav-decoration';
|
||||
|
||||
const RUN_KITE_ATTEMPTS = 30;
|
||||
const RUN_KITE_INTERVAL = 2500;
|
||||
@ -236,6 +237,8 @@ export const Kite = {
|
||||
})
|
||||
);
|
||||
|
||||
this.disposables.push(new KiteRelatedCodeDecorationsProvider());
|
||||
|
||||
this.disposables.push(
|
||||
vscode.commands.registerCommand("kite.open-copilot", () => {
|
||||
kiteOpen("kite://home");
|
||||
|
@ -1,14 +1,14 @@
|
||||
'use strict';
|
||||
|
||||
const expect = require('expect.js');
|
||||
const {kite} = require('../src/kite');
|
||||
const expect = require('chai').expect;
|
||||
const kite = require('../src/kite');
|
||||
const sinon = require('sinon');
|
||||
const vscode = require('vscode');
|
||||
const KiteAPI = require('kite-api');
|
||||
const {withKite} = require('kite-api/test/helpers/kite');
|
||||
const {waitsFor} = require('./helpers');
|
||||
const { withKite } = require('kite-api/test/helpers/kite');
|
||||
const { waitsFor } = require('./helpers');
|
||||
|
||||
withKite({running: false}, () => {
|
||||
withKite({ running: false }, () => {
|
||||
let spy, spy2;
|
||||
|
||||
describe('when startKiteAtStartup is disabled', () => {
|
||||
@ -18,12 +18,12 @@ withKite({running: false}, () => {
|
||||
startKiteAtStartup: false,
|
||||
loggingLevel: 'info',
|
||||
get(key) {
|
||||
return this[key]
|
||||
return this[key];
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
spy = sinon.spy(KiteAPI, 'runKiteAndWait');
|
||||
kite._activate();
|
||||
kite.activate({ globalState: {}});
|
||||
});
|
||||
|
||||
afterEach('package deactivation', () => {
|
||||
@ -44,12 +44,12 @@ withKite({running: false}, () => {
|
||||
startKiteEngineOnStartup: true,
|
||||
loggingLevel: 'info',
|
||||
get(key) {
|
||||
return this[key]
|
||||
return this[key];
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
spy = sinon.spy(KiteAPI, 'runKiteAndWait');
|
||||
kite._activate();
|
||||
kite.activate({ globalState: {}});
|
||||
});
|
||||
|
||||
afterEach('package deactivation', () => {
|
||||
|
133
test/codenav-decoration.test.ts
Normal file
133
test/codenav-decoration.test.ts
Normal file
@ -0,0 +1,133 @@
|
||||
import {
|
||||
DecorationOptions,
|
||||
MarkdownString,
|
||||
Position,
|
||||
Selection,
|
||||
workspace,
|
||||
window,
|
||||
} from 'vscode';
|
||||
|
||||
import * as path from 'path';
|
||||
|
||||
import { assert } from 'chai';
|
||||
import * as sinon from 'sinon';
|
||||
|
||||
import * as KiteAPI from 'kite-api';
|
||||
import KiteRelatedCodeDecorationsProvider from '../src/codenav-decoration';
|
||||
|
||||
describe('KiteRelatedCodeDecorationsProvider', () => {
|
||||
|
||||
it('hooks into the onDidChangeTextEditorSelection callback when initialized', () => {
|
||||
const onDidChangeTextEditorSelection = sinon.spy();
|
||||
new KiteRelatedCodeDecorationsProvider({ onDidChangeTextEditorSelection });
|
||||
|
||||
assert.isTrue(onDidChangeTextEditorSelection.called);
|
||||
assert.isFunction(onDidChangeTextEditorSelection.calledWith);
|
||||
});
|
||||
|
||||
describe("for various line decoration API responses", () => {
|
||||
let setDecorationSpy: sinon.SinonSpy;
|
||||
let getLineDecorationStub: sinon.SinonStub;
|
||||
let provider: KiteRelatedCodeDecorationsProvider;
|
||||
let fireEvent: () => Promise<void>;
|
||||
beforeEach(async () => {
|
||||
getLineDecorationStub = sinon.stub(KiteAPI, "getLineDecoration");
|
||||
provider = new KiteRelatedCodeDecorationsProvider(window);
|
||||
({ setDecorationSpy, fireEvent } = await setupDocument(provider));
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
getLineDecorationStub.reset();
|
||||
getLineDecorationStub.restore();
|
||||
setDecorationSpy.restore();
|
||||
});
|
||||
|
||||
it('sets the decoration when project_ready === true', async () => {
|
||||
const inlineMessage = "Find related code in kiteco";
|
||||
const hoverMessage = "Search for related code in kiteco which may be related to this line";
|
||||
getLineDecorationStub.callsFake(() => {
|
||||
return {
|
||||
inline_message: inlineMessage,
|
||||
hover_message: hoverMessage,
|
||||
project_ready: true,
|
||||
};
|
||||
});
|
||||
await fireEvent();
|
||||
const opts: DecorationOptions[] = setDecorationSpy.lastCall.args[1];
|
||||
|
||||
assert.isAbove(opts.length, 0, "Last call should include options, which shows the decoration");
|
||||
assert.include((opts[0].hoverMessage as MarkdownString).value, hoverMessage);
|
||||
assert.include(opts[0].renderOptions.after.contentText, inlineMessage);
|
||||
});
|
||||
|
||||
it('does not set the decoration when enableLineDecoration === false', async () => {
|
||||
const getConfigurationStub = sinon.stub(provider, "enabled").callsFake(() => false);
|
||||
await fireEvent();
|
||||
|
||||
assert.isFalse(getLineDecorationStub.called);
|
||||
assert.isFalse(setDecorationSpy.called);
|
||||
|
||||
getConfigurationStub.restore();
|
||||
});
|
||||
|
||||
it('does not set the decoration when project_ready === false', async () => {
|
||||
getLineDecorationStub.callsFake(() => {
|
||||
return {
|
||||
inline_message: "",
|
||||
hover_message: "",
|
||||
project_ready: false,
|
||||
};
|
||||
});
|
||||
await fireEvent();
|
||||
|
||||
setDecorationSpy.getCalls().forEach(call => {
|
||||
assert.deepEqual(call.args[1], [], "should have never been called with options");
|
||||
});
|
||||
});
|
||||
|
||||
it('does not rerequest the decoration when project_ready === undefined', async () => {
|
||||
getLineDecorationStub.callsFake(() => {
|
||||
return {
|
||||
inline_message: "",
|
||||
hover_message: "",
|
||||
project_ready: undefined,
|
||||
};
|
||||
});
|
||||
await fireEvent();
|
||||
assert.isTrue(getLineDecorationStub.calledOnce);
|
||||
|
||||
await fireEvent();
|
||||
assert.isAtMost(getLineDecorationStub.callCount, 1);
|
||||
|
||||
setDecorationSpy.getCalls().forEach(call => {
|
||||
assert.deepEqual(call.args[1], [], "setDecoration should not have been called with options");
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
async function setupDocument(
|
||||
decorationProvider: KiteRelatedCodeDecorationsProvider
|
||||
) : Promise<{
|
||||
setDecorationSpy: sinon.SinonSpy,
|
||||
fireEvent: () => Promise<void>
|
||||
}> {
|
||||
const testDocument = await workspace.openTextDocument(
|
||||
path.resolve(__dirname, "..", "..", "test", "codenav-decoration.test.ts")
|
||||
);
|
||||
const textEditor = await window.showTextDocument(testDocument);
|
||||
return {
|
||||
setDecorationSpy: sinon.spy(textEditor, "setDecorations"),
|
||||
fireEvent: () => {
|
||||
return decorationProvider.onDidChangeTextEditorSelection({
|
||||
textEditor,
|
||||
selections: [
|
||||
new Selection(
|
||||
new Position(0,0),
|
||||
new Position(0,0),
|
||||
),
|
||||
]
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
@ -1,25 +1,31 @@
|
||||
const fs = require('fs');
|
||||
const expect = require('expect.js');
|
||||
const vscode = require('vscode');
|
||||
const {fixtureURI, Kite} = require('./helpers');
|
||||
import fs from 'fs';
|
||||
import vscode from 'vscode';
|
||||
|
||||
const {withKite, withKiteRoutes} = require('kite-api/test/helpers/kite');
|
||||
const {fakeResponse} = require('kite-api/test/helpers/http');
|
||||
import { assert } from 'chai';
|
||||
import { withKite, withKiteRoutes } from 'kite-api/test/helpers/kite';
|
||||
import { fakeResponse } from 'kite-api/test/helpers/http';
|
||||
|
||||
const KiteCompletionProvider = require('../src/completion');
|
||||
import { fixtureURI, Kite } from './helpers';
|
||||
import KiteCompletionProvider from '../src/completion';
|
||||
|
||||
const mockWindow = {
|
||||
activeTextEditor: {
|
||||
selection: new vscode.Selection(new vscode.Position(19, 13), new vscode.Position(19,13))
|
||||
}
|
||||
};
|
||||
|
||||
describe('KiteCompletionProvider', () => {
|
||||
let provider;
|
||||
|
||||
beforeEach(() => {
|
||||
provider = new KiteCompletionProvider(Kite, true);
|
||||
provider = new KiteCompletionProvider(Kite, ['a'], ['('], mockWindow);
|
||||
});
|
||||
withKite({reachable: true}, () => {
|
||||
withKite({ reachable: true }, () => {
|
||||
describe('when the endpoints returns some completions', () => {
|
||||
withKiteRoutes([
|
||||
[
|
||||
o => /\/clientapi\/editor\/completions/.test(o.path),
|
||||
o => fakeResponse(200, fs.readFileSync(fixtureURI('completions.json').toString()))
|
||||
o => /\/clientapi\/editor\/complete/.test(o.path),
|
||||
() => fakeResponse(200, fs.readFileSync(fixtureURI('completions.json').toString()))
|
||||
]
|
||||
]);
|
||||
|
||||
@ -27,17 +33,17 @@ describe('KiteCompletionProvider', () => {
|
||||
const uri = vscode.Uri.file(fixtureURI('sample.py'));
|
||||
|
||||
return vscode.workspace.openTextDocument(uri)
|
||||
.then(doc => provider.provideCompletionItems(doc, new vscode.Position(19, 13), null))
|
||||
.then(res => {
|
||||
expect(res.length).to.eql(2);
|
||||
.then(doc => provider.provideCompletionItems(doc, new vscode.Position(19, 13), null, { triggerCharacter: '' }))
|
||||
.then(({ items }) => {
|
||||
assert.equal(items.length, 2);
|
||||
|
||||
expect(res[0].label).to.eql('⟠ dumps');
|
||||
expect(res[0].insertText).to.eql('idumps');
|
||||
expect(res[0].sortText).to.eql('0');
|
||||
assert.equal(items[0].label, 'json.dumps');
|
||||
assert.equal(items[0].insertText, 'dumps');
|
||||
assert.equal(items[0].sortText, '0');
|
||||
|
||||
expect(res[1].label).to.eql('⟠ dump');
|
||||
expect(res[1].insertText).to.eql('idump');
|
||||
expect(res[1].sortText).to.eql('1');
|
||||
assert.include(items[1].label, 'json.dumps(「obj」)');
|
||||
assert.equal(items[1].insertText.value, 'dumps(${1:「obj」})$0');
|
||||
assert.equal(items[1].sortText, '1');
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -46,18 +52,16 @@ describe('KiteCompletionProvider', () => {
|
||||
withKiteRoutes([
|
||||
[
|
||||
o => /\/clientapi\/editor\/completions/.test(o.path),
|
||||
o => fakeResponse(404)
|
||||
() => fakeResponse(404)
|
||||
]
|
||||
]);
|
||||
|
||||
it('returns null', () => {
|
||||
it('returns empty array', () => {
|
||||
const uri = vscode.Uri.file(fixtureURI('sample.py'));
|
||||
|
||||
return vscode.workspace.openTextDocument(uri)
|
||||
.then(doc => provider.provideCompletionItems(doc, new vscode.Position(19, 13), null))
|
||||
.then(res => {
|
||||
expect(res).to.eql([]);
|
||||
});
|
||||
.then(doc => provider.provideCompletionItems(doc, new vscode.Position(19, 13), null, { triggerCharacter: '' }))
|
||||
.then(res => assert.deepEqual(res, []));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,12 +1,12 @@
|
||||
const fs = require('fs');
|
||||
const expect = require('expect.js');
|
||||
const vscode = require('vscode');
|
||||
const {fixtureURI, Kite} = require('./helpers');
|
||||
import fs from 'fs';
|
||||
import vscode from 'vscode';
|
||||
|
||||
const {withKite, withKiteRoutes} = require('kite-api/test/helpers/kite');
|
||||
const {fakeResponse} = require('kite-api/test/helpers/http');
|
||||
import { expect } from 'chai';
|
||||
import { withKite, withKiteRoutes } from 'kite-api/test/helpers/kite';
|
||||
import { fakeResponse } from 'kite-api/test/helpers/http';
|
||||
|
||||
const KiteDefinitionProvider = require('../src/definition');
|
||||
import { fixtureURI, Kite } from './helpers';
|
||||
import KiteDefinitionProvider from '../src/definition';
|
||||
|
||||
describe('KiteDefinitionProvider', () => {
|
||||
let provider;
|
||||
@ -14,12 +14,12 @@ describe('KiteDefinitionProvider', () => {
|
||||
beforeEach(() => {
|
||||
provider = new KiteDefinitionProvider(Kite, true);
|
||||
});
|
||||
withKite({reachable: true}, () => {
|
||||
withKite({ reachable: true }, () => {
|
||||
describe('when the endpoints returns a definition', () => {
|
||||
withKiteRoutes([
|
||||
[
|
||||
o => /\/api\/buffer\/vscode\/.*\/hover/.test(o.path),
|
||||
o => fakeResponse(200, fs.readFileSync(fixtureURI('test/increment.json').toString()))
|
||||
() => fakeResponse(200, fs.readFileSync(fixtureURI('test/increment.json').toString()))
|
||||
]
|
||||
]);
|
||||
|
||||
@ -42,7 +42,7 @@ describe('KiteDefinitionProvider', () => {
|
||||
withKiteRoutes([
|
||||
[
|
||||
o => /\/api\/buffer\/vscode\/.*\/hover/.test(o.path),
|
||||
o => fakeResponse(404)
|
||||
() => fakeResponse(404)
|
||||
]
|
||||
]);
|
||||
|
||||
|
@ -1,22 +1,24 @@
|
||||
'use strict';
|
||||
|
||||
const expect = require('expect.js');
|
||||
const sinon = require('sinon');
|
||||
const EditorEvents = require('../src/events');
|
||||
const vscode = require('vscode');
|
||||
const {fixtureURI} = require('./helpers');
|
||||
import vscode from 'vscode';
|
||||
|
||||
import { expect } from 'chai';
|
||||
import sinon from 'sinon';
|
||||
|
||||
import EditorEvents from '../src/events';
|
||||
import { fixtureURI } from './helpers';
|
||||
|
||||
describe('EditorEvents', () => {
|
||||
let editor, events, Kite;
|
||||
|
||||
beforeEach(() => {
|
||||
// We're going to fake most objects that are used by the editor events
|
||||
// because of how VSCode testing environment works.
|
||||
// because of how VSCode testing environment works.
|
||||
// For instance we can't get a reference to the editor of a created document.
|
||||
Kite = {
|
||||
request: sinon.stub().returns(Promise.resolve()),
|
||||
checkState: sinon.stub().returns(Promise.resolve()),
|
||||
}
|
||||
};
|
||||
|
||||
const uri = vscode.Uri.file(fixtureURI('sample.py'));
|
||||
|
||||
@ -28,7 +30,7 @@ describe('EditorEvents', () => {
|
||||
start: new vscode.Position(0,0),
|
||||
end: new vscode.Position(0,0),
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
events = new EditorEvents(Kite, editor);
|
||||
});
|
||||
@ -41,10 +43,10 @@ describe('EditorEvents', () => {
|
||||
])
|
||||
.then(() => {
|
||||
expect(Kite.request.callCount).to.eql(1);
|
||||
|
||||
|
||||
const [, json] = Kite.request.getCall(0).args;
|
||||
const payload = JSON.parse(json);
|
||||
expect(payload.action).to.eql('edit')
|
||||
expect(payload.action).to.eql('edit');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
69
test/fixtures/completions.json
vendored
69
test/fixtures/completions.json
vendored
@ -1,32 +1,49 @@
|
||||
{
|
||||
"language": "python",
|
||||
"offset_encoding": "utf-32",
|
||||
|
||||
"completions": [
|
||||
{
|
||||
"display": "dumps",
|
||||
"insert": "idumps",
|
||||
"snippet": {
|
||||
"text": "dumps",
|
||||
"placeholders": []
|
||||
},
|
||||
"replace": {
|
||||
"begin": 17,
|
||||
"end": 18
|
||||
},
|
||||
"display": "json.dumps",
|
||||
|
||||
"web_id": "json.dumps",
|
||||
"local_id": "python;;;;json.dumps",
|
||||
|
||||
"hint": "function",
|
||||
"id": "json.dumps",
|
||||
"documentation_text": "some dumps documentation",
|
||||
"symbol": {
|
||||
"value": [
|
||||
{
|
||||
"repr": "json.dumps"
|
||||
}
|
||||
]
|
||||
}
|
||||
}, {
|
||||
"display": "dump",
|
||||
"insert": "idump",
|
||||
"hint": "function",
|
||||
"id": "json.dump",
|
||||
"documentation_text": "some dump documentation",
|
||||
"symbol": {
|
||||
"value": [
|
||||
{
|
||||
"repr": "json.dump"
|
||||
}
|
||||
]
|
||||
}
|
||||
"documentation": {
|
||||
"text": "..."
|
||||
},
|
||||
"smart": false,
|
||||
|
||||
"children": [
|
||||
{
|
||||
"snippet": {
|
||||
"text": "dumps(「obj」)",
|
||||
"placeholders": [{
|
||||
"begin": 6,
|
||||
"end": 11
|
||||
}]
|
||||
},
|
||||
"replace": {
|
||||
"begin": 17,
|
||||
"end": 18
|
||||
},
|
||||
"display": "json.dumps(「obj」)",
|
||||
|
||||
"hint": "function",
|
||||
"documentation": {
|
||||
"text": "..."
|
||||
},
|
||||
"smart": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,8 @@
|
||||
"use strict";
|
||||
|
||||
const path = require("path");
|
||||
const sinon = require("sinon");
|
||||
const Logger = require("kite-connector/lib/logger");
|
||||
const KiteAPI = require("kite-api");
|
||||
const { promisifyReadResponse } = require("../src/utils");
|
||||
const { withKiteRoutes } = require("kite-api/test/helpers/kite");
|
||||
const { fakeResponse } = require("kite-api/test/helpers/http");
|
||||
|
||||
before(() => {
|
||||
sinon.stub(Logger, "log");
|
||||
});
|
||||
|
||||
const Kite = {
|
||||
request(req, data) {
|
||||
|
@ -1,11 +1,12 @@
|
||||
const fs = require('fs');
|
||||
const expect = require('expect.js');
|
||||
const vscode = require('vscode');
|
||||
const {fixtureURI, Kite} = require('./helpers');
|
||||
import fs from 'fs';
|
||||
import vscode from 'vscode';
|
||||
|
||||
const {withKite, withKiteRoutes} = require('kite-api/test/helpers/kite');
|
||||
const {fakeResponse} = require('kite-api/test/helpers/http');
|
||||
const KiteHoverProvider = require('../src/hover');
|
||||
import { assert } from 'chai';
|
||||
import { withKite, withKiteRoutes } from 'kite-api/test/helpers/kite';
|
||||
import { fakeResponse } from 'kite-api/test/helpers/http';
|
||||
|
||||
import { fixtureURI, Kite } from './helpers';
|
||||
import KiteHoverProvider from '../src/hover';
|
||||
|
||||
describe('KiteHoverProvider', () => {
|
||||
let provider;
|
||||
@ -13,12 +14,12 @@ describe('KiteHoverProvider', () => {
|
||||
beforeEach(() => {
|
||||
provider = new KiteHoverProvider(Kite, true);
|
||||
});
|
||||
withKite({reachable: true}, () => {
|
||||
withKite({ reachable: true }, () => {
|
||||
describe('for a python function with a definition', () => {
|
||||
withKiteRoutes([
|
||||
[
|
||||
o => /\/api\/buffer\/vscode\/.*\/hover/.test(o.path),
|
||||
o => fakeResponse(200, fs.readFileSync(fixtureURI('test/increment.json').toString()))
|
||||
() => fakeResponse(200, fs.readFileSync(fixtureURI('test/increment.json').toString()))
|
||||
]
|
||||
]);
|
||||
|
||||
@ -27,10 +28,12 @@ describe('KiteHoverProvider', () => {
|
||||
|
||||
return vscode.workspace.openTextDocument(uri)
|
||||
.then(doc => provider.provideHover(doc, new vscode.Position(19, 13), null))
|
||||
.then(res => {
|
||||
expect(res.contents.length).to.eql(1);
|
||||
.then(({ contents }) => {
|
||||
assert.equal(contents.length, 1);
|
||||
const contentString = contents[0].value;
|
||||
|
||||
// TODO(Daniel): Content tests
|
||||
assert.include(contentString, '[Docs](command:kite.more-position?{"position":{"line":19,"character":13},"source":"Hover"}');
|
||||
assert.include(contentString, '[Def](command:kite.def?{"file":"sample.py","line":50,"source":"Hover"})');
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -39,7 +42,7 @@ describe('KiteHoverProvider', () => {
|
||||
withKiteRoutes([
|
||||
[
|
||||
o => /\/api\/buffer\/vscode\/.*\/hover/.test(o.path),
|
||||
o => fakeResponse(200, fs.readFileSync(fixtureURI('test/increment-no-id-no-def.json').toString()))
|
||||
() => fakeResponse(200, fs.readFileSync(fixtureURI('test/increment-no-id-no-def.json').toString()))
|
||||
]
|
||||
]);
|
||||
|
||||
@ -48,19 +51,21 @@ describe('KiteHoverProvider', () => {
|
||||
|
||||
return vscode.workspace.openTextDocument(uri)
|
||||
.then(doc => provider.provideHover(doc, new vscode.Position(19, 13), null))
|
||||
.then(res => {
|
||||
expect(res.contents.length).to.eql(1);
|
||||
.then(({ contents }) => {
|
||||
assert.equal(contents.length, 1);
|
||||
const contentString = contents[0].value;
|
||||
|
||||
// TODO(Daniel): Content tests
|
||||
assert.include(contentString, '[Docs](command:kite.more-position?{"position":{"line":19,"character":13},"source":"Hover"}');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('for a python module', () => {
|
||||
const osjson = fs.readFileSync(fixtureURI('os.json').toString());
|
||||
withKiteRoutes([
|
||||
[
|
||||
o => /\/api\/buffer\/vscode\/.*\/hover/.test(o.path),
|
||||
o => fakeResponse(200, fs.readFileSync(fixtureURI('os.json').toString()))
|
||||
() => fakeResponse(200, osjson)
|
||||
]
|
||||
]);
|
||||
|
||||
@ -69,17 +74,26 @@ describe('KiteHoverProvider', () => {
|
||||
|
||||
return vscode.workspace.openTextDocument(uri)
|
||||
.then(doc => provider.provideHover(doc, new vscode.Position(19, 13), null))
|
||||
.then(res => {
|
||||
// TODO(Daniel): Fill in tests
|
||||
.then(({ contents }) => {
|
||||
assert.equal(contents.length, 1);
|
||||
const contentString = contents[0].value;
|
||||
|
||||
assert.include(contentString, '[Docs](command:kite.more-position?{"position":{"line":19,"character":13},"source":"Hover"}');
|
||||
|
||||
const data = JSON.parse(osjson);
|
||||
data["symbol"][0]["value"].forEach(({ type }) => {
|
||||
assert.include(contentString, type);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('for an instance', () => {
|
||||
const selfjson = fs.readFileSync(fixtureURI('self.json').toString());
|
||||
withKiteRoutes([
|
||||
[
|
||||
o => /\/api\/buffer\/vscode\/.*\/hover/.test(o.path),
|
||||
o => fakeResponse(200, fs.readFileSync(fixtureURI('self.json').toString()))
|
||||
() => fakeResponse(200, selfjson)
|
||||
]
|
||||
]);
|
||||
|
||||
@ -88,8 +102,17 @@ describe('KiteHoverProvider', () => {
|
||||
|
||||
return vscode.workspace.openTextDocument(uri)
|
||||
.then(doc => provider.provideHover(doc, new vscode.Position(19, 13), null))
|
||||
.then(res => {
|
||||
// TODO(Daniel): Fill in tests
|
||||
.then(({ contents }) => {
|
||||
assert.equal(contents.length, 1);
|
||||
const contentString = contents[0].value;
|
||||
|
||||
assert.include(contentString, "[Docs](command:kite.more-position");
|
||||
assert.include(contentString, '"position":{"line":19,"character":13}');
|
||||
|
||||
const data = JSON.parse(selfjson);
|
||||
data["symbol"][0]["value"].forEach(({ type }) => {
|
||||
assert.include(contentString, type);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -98,7 +121,7 @@ describe('KiteHoverProvider', () => {
|
||||
withKiteRoutes([
|
||||
[
|
||||
o => /\/api\/buffer\/vscode\/.*\/hover/.test(o.path),
|
||||
o => fakeResponse(404)
|
||||
() => fakeResponse(404)
|
||||
]
|
||||
]);
|
||||
|
||||
@ -107,9 +130,7 @@ describe('KiteHoverProvider', () => {
|
||||
|
||||
return vscode.workspace.openTextDocument(uri)
|
||||
.then(doc => provider.provideHover(doc, new vscode.Position(19, 13), null))
|
||||
.then(res => {
|
||||
expect(res).to.be(undefined);
|
||||
});
|
||||
.then(res => assert.equal(res, undefined));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,25 +0,0 @@
|
||||
//
|
||||
// PLEASE DO NOT MODIFY / DELETE UNLESS YOU KNOW WHAT YOU ARE DOING
|
||||
//
|
||||
// This file is providing the test runner to use when running extension tests.
|
||||
// By default the test runner in use is Mocha based.
|
||||
//
|
||||
// You can provide your own test runner if you want to override it by exporting
|
||||
// a function run(testRoot: string, clb: (error:Error) => void) that the extension
|
||||
// host can call to run the tests. The test runner is expected to use console.log
|
||||
// to report the results back to the caller. When the tests are finished, return
|
||||
// a possible error to the callback or null if none.
|
||||
|
||||
process.env.NODE_ENV = "test";
|
||||
|
||||
var testRunner = require('vscode/lib/testrunner');
|
||||
|
||||
// You can directly control Mocha options by uncommenting the following lines
|
||||
// See https://github.com/mochajs/mocha/wiki/Using-mocha-programmatically#set-options for more info
|
||||
testRunner.configure({
|
||||
ui: 'bdd', // the TDD UI is being used in extension.test.js (suite, test, etc.)
|
||||
useColors: true, // colored output from test results
|
||||
timeout: 5000,
|
||||
});
|
||||
|
||||
module.exports = testRunner;
|
42
test/index.ts
Normal file
42
test/index.ts
Normal file
@ -0,0 +1,42 @@
|
||||
// This file provides the test runner to use when running extension tests,
|
||||
// based off the example in VSCode documentation.
|
||||
|
||||
process.env.NODE_ENV = "test";
|
||||
|
||||
import 'source-map-support/register';
|
||||
import * as path from 'path';
|
||||
import * as glob from 'glob';
|
||||
import Mocha = require('mocha')
|
||||
|
||||
export function run(): Promise<void> {
|
||||
const mocha = new Mocha({
|
||||
ui: 'bdd', // the TDD UI is being used in extension.test.js (suite, test, etc.)
|
||||
timeout: 5000,
|
||||
});
|
||||
mocha.useColors(true);
|
||||
|
||||
const outTestDir = path.resolve(__dirname);
|
||||
return new Promise((res, rej) => {
|
||||
glob('*.test.js', { cwd: outTestDir }, (err, files) => {
|
||||
if (err) {
|
||||
return rej(err);
|
||||
}
|
||||
|
||||
// Add files to the test suite
|
||||
files.forEach(f => mocha.addFile(path.resolve(outTestDir, f)));
|
||||
|
||||
try {
|
||||
// Run the mocha test
|
||||
mocha.run(failures => {
|
||||
if (failures > 0) {
|
||||
rej(new Error(`${failures} tests failed.`));
|
||||
} else {
|
||||
res();
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
rej(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
@ -1,37 +1,37 @@
|
||||
'use strict';
|
||||
|
||||
const expect = require('expect.js')
|
||||
const expect = require('chai').expect;
|
||||
const vscode = require('vscode');
|
||||
const {substituteFromContext, buildContext, itForExpectation, NotificationsMock} = require('../utils');
|
||||
const {waitsFor} = require('../../helpers')
|
||||
const { substituteFromContext, buildContext, itForExpectation, NotificationsMock } = require('../utils');
|
||||
const { waitsFor } = require('../../helpers');
|
||||
|
||||
module.exports = ({expectation, not, root}) => {
|
||||
module.exports = ({ expectation, not, root }) => {
|
||||
beforeEach(() => {
|
||||
const spy = vscode.window[NotificationsMock.LEVELS[expectation.properties.level]]
|
||||
const spy = vscode.window[NotificationsMock.LEVELS[expectation.properties.level]];
|
||||
const promise = waitsFor(`${expectation.properties.level} notification`, () => {
|
||||
return NotificationsMock.newNotification();
|
||||
}, 100)
|
||||
}, 100);
|
||||
|
||||
if(not) {
|
||||
return promise.then(() => {
|
||||
throw new Error(`no ${expectation.properties.level} notification, but some were found`)
|
||||
}, () => {})
|
||||
throw new Error(`no ${expectation.properties.level} notification, but some were found`);
|
||||
}, () => {});
|
||||
} else {
|
||||
return promise
|
||||
return promise;
|
||||
}
|
||||
});
|
||||
|
||||
const block = () => {
|
||||
if(!not) {
|
||||
expect(NotificationsMock.lastNotification.level).to.eql(expectation.properties.level)
|
||||
|
||||
expect(NotificationsMock.lastNotification.level).to.eql(expectation.properties.level);
|
||||
|
||||
if(expectation.properties.message) {
|
||||
const message = substituteFromContext(expectation.properties.message, buildContext(root))
|
||||
|
||||
const message = substituteFromContext(expectation.properties.message, buildContext(root));
|
||||
|
||||
expect(NotificationsMock.lastNotification.message).to.eql(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
itForExpectation(expectation, block);
|
||||
}
|
||||
};
|
||||
|
@ -1,17 +1,17 @@
|
||||
'use strict';
|
||||
|
||||
const expect = require('expect.js');
|
||||
const {itForExpectation, NotificationsMock} = require('../utils');
|
||||
const expect = require('chai').expect;
|
||||
const { itForExpectation, NotificationsMock } = require('../utils');
|
||||
|
||||
module.exports = ({expectation, not}) => {
|
||||
module.exports = ({ expectation, not }) => {
|
||||
const block = () => {
|
||||
if(not) {
|
||||
expect(NotificationsMock.notificationsForLevel(expectation.properties.level).length).not.to.eql(expectation.properties.count)
|
||||
expect(NotificationsMock.notificationsForLevel(expectation.properties.level).length).not.to.eql(expectation.properties.count);
|
||||
} else {
|
||||
expect(NotificationsMock.notificationsForLevel(expectation.properties.level).length).to.eql(expectation.properties.count)
|
||||
expect(NotificationsMock.notificationsForLevel(expectation.properties.level).length).to.eql(expectation.properties.count);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
itForExpectation(expectation, block);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1,14 +1,11 @@
|
||||
'use strict';
|
||||
|
||||
const expect = require('expect.js')
|
||||
const vscode = require('vscode');
|
||||
const http = require('http');
|
||||
const expect = require('chai').expect;
|
||||
const KiteAPI = require('kite-api');
|
||||
const KiteConnect = require('kite-connector');
|
||||
const {loadPayload, substituteFromContext, buildContext, itForExpectation, inLiveEnvironment} = require('../utils');
|
||||
const {waitsFor, formatCall} = require('../../helpers')
|
||||
const { loadPayload, substituteFromContext, buildContext, itForExpectation, inLiveEnvironment } = require('../utils');
|
||||
const { waitsFor, formatCall } = require('../../helpers');
|
||||
|
||||
let closeMatches, calls;
|
||||
let closeMatches;
|
||||
const getDesc = (expectation, root) => () => {
|
||||
const base = [
|
||||
'request to',
|
||||
@ -20,21 +17,21 @@ const getDesc = (expectation, root) => () => {
|
||||
|
||||
if(expectation.properties.body) {
|
||||
base.push('with');
|
||||
base.push(JSON.stringify(substituteFromContext(loadPayload(expectation.properties.body), buildContext(root))))
|
||||
base.push(JSON.stringify(substituteFromContext(loadPayload(expectation.properties.body), buildContext(root))));
|
||||
}
|
||||
|
||||
if (closeMatches.length > 0) {
|
||||
base.push('\nbut some calls were close');
|
||||
closeMatches.forEach((call) => {
|
||||
base.push(`\n - ${formatCall(call)}`)
|
||||
base.push(`\n - ${formatCall(call)}`);
|
||||
});
|
||||
} else {
|
||||
// .map(({args: [{path, method}, payload]}) => `${method || 'GET'} ${path} '${payload || ''}'`));
|
||||
base.push(`\nbut no calls were anywhere close\n${KiteAPI.request.getCalls().map(c => {
|
||||
let [{path, method}, payload] = c.args;
|
||||
let [{ path, method }, payload] = c.args;
|
||||
method = method || 'GET';
|
||||
|
||||
return `- ${formatCall({path, method, payload})}`
|
||||
return `- ${formatCall({ path, method, payload })}`;
|
||||
}).join('\n')}`);
|
||||
}
|
||||
|
||||
@ -51,7 +48,7 @@ const getNotDesc = (expectation, root) => {
|
||||
|
||||
if(expectation.properties.body) {
|
||||
base.push('with');
|
||||
base.push(JSON.stringify(substituteFromContext(loadPayload(expectation.properties.body), buildContext(root))))
|
||||
base.push(JSON.stringify(substituteFromContext(loadPayload(expectation.properties.body), buildContext(root))));
|
||||
}
|
||||
|
||||
base.push('\nbut calls were found');
|
||||
@ -79,7 +76,7 @@ const mostRecentCallMatching = (data, exPath, exMethod, exPayload, context = {},
|
||||
if (calls.length === 0) { return false; }
|
||||
|
||||
return calls.reverse().reduce((b, c, i, a) => {
|
||||
let {path, method, body} = c;
|
||||
let { path, method, body } = c;
|
||||
method = method || 'GET';
|
||||
|
||||
// b is false here only if we found a call that partially matches
|
||||
@ -92,7 +89,7 @@ const mostRecentCallMatching = (data, exPath, exMethod, exPayload, context = {},
|
||||
|
||||
if (path === exPath) {
|
||||
if (method === exMethod) {
|
||||
closeMatches.push({path, method, body});
|
||||
closeMatches.push({ path, method, body });
|
||||
if (!exPayload || expect.eql(JSON.parse(body), exPayload)) {
|
||||
matched = true;
|
||||
return true;
|
||||
@ -114,11 +111,11 @@ const mostRecentCallMatching = (data, exPath, exMethod, exPayload, context = {},
|
||||
}, true);
|
||||
};
|
||||
|
||||
module.exports = ({expectation, not, root}) => {
|
||||
module.exports = ({ expectation, not, root }) => {
|
||||
beforeEach('request matching', function() {
|
||||
const promise = waitsFor(getDesc(expectation, root), () => {
|
||||
if (inLiveEnvironment()) {
|
||||
return KiteAPI.requestJSON({path: '/testapi/request-history'})
|
||||
return KiteAPI.requestJSON({ path: '/testapi/request-history' })
|
||||
.then((data) => {
|
||||
if (!mostRecentCallMatching(
|
||||
data,
|
||||
@ -144,7 +141,7 @@ module.exports = ({expectation, not, root}) => {
|
||||
if(not) {
|
||||
return promise.then(() => {
|
||||
throw new Error(getNotDesc(expectation, root));
|
||||
}, () => {})
|
||||
}, () => {});
|
||||
} else {
|
||||
return promise;
|
||||
}
|
||||
|
@ -1,10 +1,8 @@
|
||||
'use strict';
|
||||
|
||||
const expect = require('expect.js')
|
||||
const vscode = require('vscode');
|
||||
const http = require('http');
|
||||
const {loadPayload, substituteFromContext, buildContext, itForExpectation, inLiveEnvironment} = require('../utils');
|
||||
const {waitsFor} = require('../../helpers')
|
||||
const expect = require('chai').expect;
|
||||
const { loadPayload, substituteFromContext, buildContext, itForExpectation, inLiveEnvironment } = require('../utils');
|
||||
const { waitsFor } = require('../../helpers');
|
||||
const KiteAPI = require('kite-api');
|
||||
|
||||
const callsMatching = (data, exPath, exMethod, exPayload, context={}) => {
|
||||
@ -16,7 +14,7 @@ const callsMatching = (data, exPath, exMethod, exPayload, context={}) => {
|
||||
};
|
||||
});
|
||||
|
||||
exPath = substituteFromContext(exPath, context)
|
||||
exPath = substituteFromContext(exPath, context);
|
||||
exPayload = exPayload && substituteFromContext(loadPayload(exPayload), context);
|
||||
|
||||
// console.log('--------------------')
|
||||
@ -25,20 +23,20 @@ const callsMatching = (data, exPath, exMethod, exPayload, context={}) => {
|
||||
if(calls.length === 0) { return false; }
|
||||
|
||||
return calls.reverse().filter((c) => {
|
||||
let {path, method, body} = c;
|
||||
method = method || 'GET'
|
||||
let { path, method, body } = c;
|
||||
method = method || 'GET';
|
||||
|
||||
// console.log(path, method, payload)
|
||||
|
||||
return path === exPath && method === exMethod && (!exPayload || expect.eql(JSON.parse(body), exPayload))
|
||||
return path === exPath && method === exMethod && (!exPayload || expect.eql(JSON.parse(body), exPayload));
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = ({expectation, not, root}) => {
|
||||
module.exports = ({ expectation, not, root }) => {
|
||||
beforeEach('request count', () => {
|
||||
const promise = waitsFor(`${expectation.properties.count} requests to '${expectation.properties.path}' for test '${expectation.description}'`, () => {
|
||||
if (inLiveEnvironment()) {
|
||||
return KiteAPI.requestJSON({path: '/testapi/request-history'})
|
||||
return KiteAPI.requestJSON({ path: '/testapi/request-history' })
|
||||
.then((data) => {
|
||||
const calls = callsMatching(
|
||||
data,
|
||||
@ -61,7 +59,7 @@ module.exports = ({expectation, not, root}) => {
|
||||
|
||||
return calls.length === expectation.properties.count;
|
||||
}
|
||||
}, 3000)
|
||||
}, 3000)
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
throw err;
|
||||
@ -75,7 +73,7 @@ module.exports = ({expectation, not, root}) => {
|
||||
expectation.properties.body,
|
||||
buildContext(root)).length;
|
||||
throw new Error(`no ${expectation.properties.count} requests to '${expectation.properties.path}' for test '${expectation.description}' but ${callsCount} were found`);
|
||||
}, () => {})
|
||||
}, () => {});
|
||||
} else {
|
||||
return promise;
|
||||
}
|
||||
|
32
test/runTests.js
Normal file
32
test/runTests.js
Normal file
@ -0,0 +1,32 @@
|
||||
import * as path from 'path';
|
||||
import { runTests, downloadAndUnzipVSCode } from 'vscode-test';
|
||||
|
||||
async function main() {
|
||||
try {
|
||||
const __dirname = path.resolve(path.dirname(''));
|
||||
// The folder containing the Extension Manifest package.json
|
||||
// Passed to `--extensionDevelopmentPath`
|
||||
const extensionDevelopmentPath = path.resolve(__dirname, '.');
|
||||
|
||||
// The path to the extension test runner script
|
||||
// Passed to --extensionTestsPath
|
||||
const extensionTestsPath = path.resolve(__dirname, './out/test');
|
||||
|
||||
const vscodeExecutablePath = await downloadAndUnzipVSCode('stable');
|
||||
console.log("Finished downloading VSCode to ", vscodeExecutablePath);
|
||||
|
||||
const exitCode = await runTests({
|
||||
vscodeExecutablePath,
|
||||
extensionDevelopmentPath,
|
||||
extensionTestsPath,
|
||||
launchArgs: ['--disable-extensions']
|
||||
});
|
||||
|
||||
console.log("Finished running tests with exit code", exitCode);
|
||||
} catch (err) {
|
||||
console.error('Failed to run tests: ', err);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
@ -1,13 +1,13 @@
|
||||
const fs = require('fs');
|
||||
const expect = require('expect.js');
|
||||
const expect = require('chai').expect;
|
||||
const vscode = require('vscode');
|
||||
const {fixtureURI, Kite} = require('./helpers');
|
||||
const { fixtureURI, Kite } = require('./helpers');
|
||||
|
||||
const {withKite, withKiteRoutes} = require('kite-api/test/helpers/kite');
|
||||
const {fakeResponse} = require('kite-api/test/helpers/http');
|
||||
const { withKite, withKiteRoutes } = require('kite-api/test/helpers/kite');
|
||||
const { fakeResponse } = require('kite-api/test/helpers/http');
|
||||
|
||||
|
||||
const KiteSignatureProvider = require('../src/signature');
|
||||
const KiteSignatureProvider = require('../src/signature').default;
|
||||
|
||||
describe('KiteSignatureProvider', () => {
|
||||
let provider;
|
||||
@ -15,12 +15,12 @@ describe('KiteSignatureProvider', () => {
|
||||
beforeEach(() => {
|
||||
provider = new KiteSignatureProvider(Kite, true);
|
||||
});
|
||||
withKite({reachable: true}, () => {
|
||||
withKite({ reachable: true }, () => {
|
||||
describe('for a python function with a signature', () => {
|
||||
withKiteRoutes([
|
||||
[
|
||||
o => /\/clientapi\/editor\/signatures/.test(o.path),
|
||||
o => fakeResponse(200, fs.readFileSync(fixtureURI('plot-signatures.json').toString()))
|
||||
() => fakeResponse(200, fs.readFileSync(fixtureURI('plot-signatures.json').toString()))
|
||||
]
|
||||
]);
|
||||
|
||||
@ -30,14 +30,14 @@ describe('KiteSignatureProvider', () => {
|
||||
return vscode.workspace.openTextDocument(uri)
|
||||
.then(doc => provider.provideSignatureHelp(doc, new vscode.Position(19, 13), null))
|
||||
.then(res => {
|
||||
expect(res.signatures.length).to.eql(1);
|
||||
expect(res.signatures[0].label).to.eql('⟠ plot(x:list|uint64, y:list|str)');
|
||||
expect(res.signatures[0].parameters.length).to.eql(2);
|
||||
expect(res.signatures[0].parameters[0].label).to.eql('x:list|uint64');
|
||||
expect(res.signatures[0].parameters[1].label).to.eql('y:list|str');
|
||||
expect(res.signatures.length).to.equal(1);
|
||||
expect(res.signatures[0].label).to.equal('⟠ plot(x:list|uint64, y:list|str)');
|
||||
expect(res.signatures[0].parameters.length).to.equal(2);
|
||||
expect(res.signatures[0].parameters[0].label).to.equal('x:list|uint64');
|
||||
expect(res.signatures[0].parameters[1].label).to.equal('y:list|str');
|
||||
|
||||
expect(res.activeParameter).to.eql(1);
|
||||
expect(res.activeSignature).to.eql(0);
|
||||
expect(res.activeParameter).to.equal(1);
|
||||
expect(res.activeSignature).to.equal(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -46,7 +46,7 @@ describe('KiteSignatureProvider', () => {
|
||||
withKiteRoutes([
|
||||
[
|
||||
o => /\/clientapi\/editor\/signatures/.test(o.path),
|
||||
o => fakeResponse(404)
|
||||
() => fakeResponse(404)
|
||||
]
|
||||
]);
|
||||
|
||||
@ -56,7 +56,7 @@ describe('KiteSignatureProvider', () => {
|
||||
return vscode.workspace.openTextDocument(uri)
|
||||
.then(doc => provider.provideSignatureHelp(doc, new vscode.Position(19, 13), null))
|
||||
.then(res => {
|
||||
expect(res).to.be(null);
|
||||
expect(res).to.equal(null);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
14
tsconfig.json
Normal file
14
tsconfig.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"moduleResolution": "node",
|
||||
"compilerOptions": {
|
||||
"outDir": "./dist/",
|
||||
"sourceMap": true,
|
||||
"noImplicitAny": false,
|
||||
"module": "commonjs",
|
||||
"target": "es6",
|
||||
"allowJs": true
|
||||
},
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
Loading…
Reference in New Issue
Block a user