Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .vscode-test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ function generateConfig(label) {
/** @type {import('@vscode/test-cli').TestConfiguration} */
let config = {
label,
files: ["out/**/*.test.js"],
files: ["dist/**/*.test.js"],
version: "insiders",
srcDir: "src",
launchArgs: [
Expand Down
10 changes: 8 additions & 2 deletions src/@types/vscode.proposed.chatParticipantAdditions.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -646,7 +646,13 @@ declare module 'vscode' {
}

export interface ChatRequest {
modeInstructions?: string;
modeInstructionsToolReferences?: readonly ChatLanguageModelToolReference[];
readonly modeInstructions?: string;
readonly modeInstructions2?: ChatRequestModeInstructions;
}

export interface ChatRequestModeInstructions {
readonly content: string;
readonly toolReferences?: readonly ChatLanguageModelToolReference[];
readonly metadata?: Record<string, boolean | string | number>;
}
}
3 changes: 3 additions & 0 deletions src/@types/vscode.proposed.chatParticipantPrivate.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,8 @@ declare module 'vscode' {

isQuotaExceeded?: boolean;

isRateLimited?: boolean;

level?: ChatErrorLevel;

code?: string;
Expand Down Expand Up @@ -239,6 +241,7 @@ declare module 'vscode' {
export class ExtendedLanguageModelToolResult extends LanguageModelToolResult {
toolResultMessage?: string | MarkdownString;
toolResultDetails?: Array<Uri | Location>;
toolMetadata?: unknown;
}

// #region Chat participant detection
Expand Down
6 changes: 6 additions & 0 deletions src/test/browser/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

// @ts-nocheck
// This file is providing the test runner to use when running extension tests.
import * as vscode from 'vscode';
require('mocha/mocha');
Expand Down
2 changes: 1 addition & 1 deletion src/test/builders/graphql/latestReviewCommitBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { LatestReviewCommitResponse } from '../../../github/graphql';

import { RateLimitBuilder } from './rateLimitBuilder';

type Repository = LatestReviewCommitResponse['repository'];
type Repository = NonNullable<LatestReviewCommitResponse['repository']>;
type PullRequest = Repository['pullRequest'];
type ViewerLatestReview = PullRequest['viewerLatestReview'];
type Commit = ViewerLatestReview['commit'];
Expand Down
2 changes: 1 addition & 1 deletion src/test/builders/graphql/pullRequestBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ const RefBuilder = createBuilderClass<Ref>()({
}),
});

type Repository = PullRequestResponse['repository'];
type Repository = NonNullable<PullRequestResponse['repository']>;
type PullRequest = Repository['pullRequest'];
type Author = PullRequest['author'];
type AssigneesConn = PullRequest['assignees'];
Expand Down
7 changes: 6 additions & 1 deletion src/test/builders/graphql/timelineEventsBuilder.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { createBuilderClass, createLink } from '../base';
import { TimelineEventsResponse } from '../../../github/graphql';

import { RateLimitBuilder } from './rateLimitBuilder';

type Repository = TimelineEventsResponse['repository'];
type Repository = NonNullable<TimelineEventsResponse['repository']>;
type PullRequest = Repository['pullRequest'];
type TimelineConn = PullRequest['timelineItems'];

Expand Down
11 changes: 8 additions & 3 deletions src/test/builders/rest/pullRequestBuilder.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { UserBuilder } from './userBuilder';
import { RefBuilder } from './refBuilder';
import { NonNullUserRefBuilder, RefBuilder } from './refBuilder';
import { createLink, createBuilderClass } from '../base';
import { OctokitCommon } from '../../../github/common';

Expand Down Expand Up @@ -40,8 +45,8 @@ export const PullRequestBuilder = createBuilderClass<PullRequestUnion>()({
closed_at: { default: '' },
merged_at: { default: '' },
merge_commit_sha: { default: '' },
head: { linked: RefBuilder },
base: { linked: RefBuilder },
head: { linked: NonNullUserRefBuilder },
base: { linked: NonNullUserRefBuilder },
draft: { default: false },
merged: { default: false },
mergeable: { default: true },
Expand Down
18 changes: 17 additions & 1 deletion src/test/builders/rest/refBuilder.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { UserBuilder } from './userBuilder';
import { RepositoryBuilder } from './repoBuilder';
import { createBuilderClass } from '../base';
import { OctokitCommon } from '../../../github/common';

type RefUnion = OctokitCommon.PullsListResponseItemHead & OctokitCommon.PullsListResponseItemBase;

export const RefBuilder = createBuilderClass<RefUnion>()({
export const RefBuilder = createBuilderClass<NonNullable<RefUnion>>()({
label: { default: 'octocat:new-feature' },
ref: { default: 'new-feature' },
user: { linked: UserBuilder },
Expand All @@ -14,4 +19,15 @@ export const RefBuilder = createBuilderClass<RefUnion>()({
repo: { linked: <any>RepositoryBuilder },
});

// Variant where user is guaranteed non-null.
type NonNullUserRef = Omit<RefUnion, 'user'> & { user: NonNullable<RefUnion['user']> };

export const NonNullUserRefBuilder = createBuilderClass<NonNullUserRef>()({
label: { default: 'octocat:new-feature' },
ref: { default: 'new-feature' },
user: { linked: UserBuilder }, // non-null guarantee
sha: { default: '0000000000000000000000000000000000000000' },
repo: { linked: <any>RepositoryBuilder },
});

export type RefBuilder = InstanceType<typeof RefBuilder>;
8 changes: 4 additions & 4 deletions src/test/builders/rest/repoBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ type License = RepoUnion['license'];
type Permissions = RepoUnion['permissions'];
type CodeOfConduct = RepoUnion['code_of_conduct'];

export const RepositoryBuilder = createBuilderClass<RepoUnion>()({
export const RepositoryBuilder = createBuilderClass<NonNullable<RepoUnion>>()({
id: { default: 0 },
node_id: { default: 'node0' },
name: { default: 'reponame' },
Expand Down Expand Up @@ -123,9 +123,9 @@ export const RepositoryBuilder = createBuilderClass<RepoUnion>()({
name: { default: 'name' },
url: { default: 'https://github.com/octocat/reponame' },
}),
forks: { default: null },
open_issues: { default: null },
watchers: { default: null },
forks: { default: 0 },
open_issues: { default: 0 },
watchers: { default: 0 },
});

export type RepositoryBuilder = InstanceType<typeof RepositoryBuilder>;
4 changes: 3 additions & 1 deletion src/test/builders/rest/userBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ type UserUnion =
| OctokitCommon.PullsListResponseItemHeadRepoOwner
| OctokitCommon.IssuesListEventsForTimelineResponseItemActor;

export const UserBuilder = createBuilderClass<Required<UserUnion>>()({
type NonNullUser = NonNullable<UserUnion>;

export const UserBuilder = createBuilderClass<NonNullUser>()({
id: { default: 0 },
node_id: { default: 'node0' },
login: { default: 'octocat' },
Expand Down
38 changes: 21 additions & 17 deletions src/test/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

// @ts-nocheck
// This file is providing the test runner to use when running extension tests.
import * as path from 'path';
import * as vscode from 'vscode';
Expand All @@ -6,20 +12,6 @@ import Mocha from 'mocha';
import { mockWebviewEnvironment } from './mocks/mockWebviewEnvironment';
import { EXTENSION_ID } from '../constants';

function addTests(mocha: Mocha, root: string): Promise<void> {
return new Promise((resolve, reject) => {
glob('**/**.test.js', { cwd: root }, (error, files) => {
if (error) {
return reject(error);
}

for (const testFile of files) {
mocha.addFile(path.join(root, testFile));
}
resolve();
});
});
}

async function runAllExtensionTests(testsRoot: string, clb: (error: Error | null, failures?: number) => void): Promise<any> {
// Ensure the dev-mode extension is activated
Expand All @@ -31,10 +23,22 @@ async function runAllExtensionTests(testsRoot: string, clb: (error: Error | null
ui: 'bdd',
color: true
});
mocha.addFile(path.resolve(testsRoot, 'globalHooks.js'));
// Load globalHooks if it exists
try {
mocha.addFile(path.resolve(testsRoot, 'globalHooks.js'));
} catch (e) {
// globalHooks might not exist in webpack bundle, ignore
}

await addTests(mocha, testsRoot);
await addTests(mocha, path.resolve(testsRoot, '../../../webviews/'));
// Import all test files using webpack's require.context
try {
// Load tests from src/test directory only
// Webview tests are compiled separately with the webview configuration
const importAll = (r: __WebpackModuleApi.RequireContext) => r.keys().forEach(r);
importAll(require.context('./', true, /\.test$/));
} catch (e) {
console.log('Error loading tests:', e);
}

if (process.env.TEST_JUNIT_XML_PATH) {
mocha.reporter('mocha-multi-reporters', {
Expand Down
9 changes: 4 additions & 5 deletions src/test/mocks/mockGitHubRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@ import { MockTelemetry } from './mockTelemetry';
import { Uri } from 'vscode';
import { LoggingOctokit, RateLogger } from '../../github/loggingOctokit';
import { mergeQuerySchemaWithShared } from '../../github/common';
import { PullRequestModel } from '../../github/pullRequestModel';
import { TimelineEvent } from '../../common/timelineEvent';

const queries = mergeQuerySchemaWithShared(require('../../github/queries.gql'), require('../../github/queriesShared.gql')) as any;

export class MockGitHubRepository extends GitHubRepository {
Expand All @@ -35,7 +34,7 @@ export class MockGitHubRepository extends GitHubRepository {

this._hub = {
octokit: new LoggingOctokit(this.queryProvider.octokit, new RateLogger(new MockTelemetry(), true)),
graphql: null,
graphql: {} as any,
};

this._metadata = Promise.resolve({
Expand Down Expand Up @@ -73,8 +72,8 @@ export class MockGitHubRepository extends GitHubRepository {
block(builder);
const responses = builder.build();

const prNumber = responses.pullRequest.repository.pullRequest.number;
const headRef = responses.pullRequest.repository.pullRequest.headRef;
const prNumber = responses.pullRequest.repository!.pullRequest.number;
const headRef = responses.pullRequest.repository?.pullRequest.headRef;

this.queryProvider.expectGraphQLQuery(
{
Expand Down
6 changes: 3 additions & 3 deletions src/test/view/prsTree.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ describe('GitHub Pull Requests view', function () {
userAgent: 'GitHub VSCode Pull Requests',
previews: ['shadow-cat-preview'],
}), new RateLogger(telemetry, true)),
graphql: null,
graphql: {} as any,
};

return github;
Expand Down Expand Up @@ -160,7 +160,7 @@ describe('GitHub Pull Requests view', function () {
);
});
}).pullRequest;
const prItem0 = await parseGraphQLPullRequest(pr0.repository.pullRequest, gitHubRepository);
const prItem0 = await parseGraphQLPullRequest(pr0.repository!.pullRequest, gitHubRepository);
const pullRequest0 = new PullRequestModel(credentialStore, telemetry, gitHubRepository, remote, prItem0);

const pr1 = gitHubRepository.addGraphQLPullRequest(builder => {
Expand All @@ -177,7 +177,7 @@ describe('GitHub Pull Requests view', function () {
);
});
}).pullRequest;
const prItem1 = await parseGraphQLPullRequest(pr1.repository.pullRequest, gitHubRepository);
const prItem1 = await parseGraphQLPullRequest(pr1.repository!.pullRequest, gitHubRepository);
const pullRequest1 = new PullRequestModel(credentialStore, telemetry, gitHubRepository, remote, prItem1);

const repository = new MockRepository();
Expand Down
1 change: 0 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
},
"exclude": [
"node_modules",
"src/test",
"webviews"
]
}
24 changes: 21 additions & 3 deletions webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -156,14 +156,12 @@ async function getWebviewConfig(mode, env, entry) {
*/
async function getExtensionConfig(target, mode, env) {
const basePath = path.join(__dirname, 'src');
const glob = require('glob');

/**
* @type WebpackConfig['plugins'] | any
*/
const plugins = [
new webpack.optimize.LimitChunkCountPlugin({
maxChunks: 1
}),
new ForkTsCheckerPlugin({
async: false,
formatter: 'basic',
Expand All @@ -190,8 +188,28 @@ async function getExtensionConfig(target, mode, env) {
const entry = {
extension: './src/extension.ts',
};

// Add test entry points
if (target === 'webworker') {
entry['test/index'] = './src/test/browser/index.ts';
} else if (target === 'node') {
// Add main test runner
entry['test/index'] = './src/test/index.ts';

// Add individual test files as separate entry points
const testFiles = glob.sync('src/test/**/*.test.ts', { cwd: __dirname });
testFiles.forEach(testFile => {
// Convert src/test/github/utils.test.ts -> test/github/utils.test
const entryName = testFile.replace('src/', '').replace('.ts', '');
entry[entryName] = `./${testFile}`;
});
}

// Don't limit chunks for node target when we have individual test files
if (target !== 'node' || !('test/index' in entry && Object.keys(entry).some(key => key.endsWith('.test')))) {
plugins.unshift(new webpack.optimize.LimitChunkCountPlugin({
maxChunks: 1
}));
}

return {
Expand Down
Loading