Skip to content
Draft
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,4 @@ testWorkspace
test-results.xml
dist
stats.json
.test-extensions
9 changes: 9 additions & 0 deletions mocharc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module.exports = {
// Configure mocha to run tests with ts-node/esm loader
require: 'ts-node/register',
extension: ['ts'],
spec: 'test/**/*.test.ts',
node_args: ['--loader=ts-node/esm'],
parallel: false, // Ensure tests run sequentially
timeout: 60000, // Set timeout to 60 seconds
}
24,099 changes: 10,838 additions & 13,261 deletions package-lock.json

Large diffs are not rendered by default.

9 changes: 8 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -796,6 +796,7 @@
}
},
"scripts": {
"ui-test": "extest setup-and-run './out/test/ui-tests/*.test.js' --code_version max --extensions_dir .test-extensions",
"vscode:prepublish": "npm run webpack-prod",
"build": "tsc",
"cleanReadme": "gulp cleanReadme",
Expand All @@ -817,6 +818,7 @@
"@azure/ms-rest-azure-env": "^2.0.0",
"@microsoft/eslint-config-azuretools": "^0.2.2",
"@microsoft/vscode-azext-dev": "^2.1.0",
"@types/chai": "^5.2.2",
"@swc/core": "^1.7.36",
"@types/deep-eql": "^4.0.0",
"@types/fs-extra": "^8.1.1",
Expand All @@ -832,20 +834,25 @@
"@vscode/test-electron": "^2.3.8",
"@vscode/vsce": "^2.19.0",
"assert": "^2.0.0",
"brace-expansion": "^4.0.1",
"chai": "^4.5.0",
"copy-webpack-plugin": "^12.0.2",
"css-loader": "^7.1.2",
"eslint": "^8.42.0",
"eslint-plugin-import": "^2.27.5",
"glob": "^7.1.6",
"glob": "^11.0.3",
"gulp": "^5.0.0",
"husky": "^7.0.2",
"minimatch": "^10.0.3",
"mocha": "^10.1.0",
"mocha-junit-reporter": "^2.0.0",
"mocha-multi-reporters": "^1.1.7",
"process": "^0.11.10",
"style-loader": "^4.0.0",
"swc-loader": "^0.2.6",
"ts-node": "^10.9.1",
"typescript": "^5.1.3",
"vscode-extension-tester": "^8.15.0",
"webpack": "^5.94.0",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^5.1.0"
Expand Down
4 changes: 4 additions & 0 deletions package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,14 +76,18 @@
"containerApps.walkthrough.gettingStarted.internal": "Open Walkthrough",
"containerApps.walkthrough.gettingStarted.title": "Getting Started with Azure Container Apps",
"containerApps.walkthrough.gettingStarted.description": "Learn to deploy a containerized application to Azure Container Apps using a sample GitHub repository.",
"containerApps.walkthrough.addWorkspaceProject": "Add a workspace project",
"containerApps.walkthrough.addWorkspaceProject.title": "Add a workspace project",
"containerApps.walkthrough.addWorkspaceProject.description": "Starting from an empty workspace, use the button below to clone a sample project from GitHub.\nYou will be prompted by Visual Studio Code at the top of the page. Answer using the provided table values.\n[Clone Repository](command:containerApps.walkthrough.addWorkspaceProject)",
"containerApps.walkthrough.azureSignIn": "Sign in to Azure",
"containerApps.walkthrough.azureSignIn.title": "Sign in to Azure",
"containerApps.walkthrough.azureSignIn.description": "Sign in using the button below.\nYou may be directed to authenticate using your browser. Return to Visual Studio Code once completed.\n[Sign in to Azure](command:containerApps.walkthrough.azureSignIn)",
"containerApps.walkthrough.deployWorkspaceProject": "Create and deploy",
"containerApps.walkthrough.deployWorkspaceProject.title": "Create and deploy",
"containerApps.walkthrough.deployWorkspaceProject.description": "Create the container app resources necessary to host the application by using the button below.\nYou will be prompted by Visual Studio Code at the top of the page. Answer using the provided table values.\n[Deploy Project from Workspace](command:containerApps.walkthrough.deployWorkspaceProject)",
"containerApps.walkthrough.exploreDetails.title": "Explore details",
"containerApps.walkthrough.exploreDetails.description": "Let's explore what we've accomplished so far.\nIn this walkthrough, the commands were provided to you directly in each step. In practice, most of these commands will need to be accessed via the Azure Resources and Workspace pane.\nUse the provided table to review and discover the real location of each command.",
"containerApps.walkthrough.cleanUpResources": "Clean up resources",
"containerApps.walkthrough.cleanUpResources.title": "Clean up resources",
"containerApps.walkthrough.cleanUpResources.description": "Remove the resources created in this walkthrough by deleting the containing resource group using the button below.\nYou will be prompted by Visual Studio Code at the top of the page. Answer using the provided table values.\n[Delete Resource Group](command:containerApps.walkthrough.cleanUpResources)"
}
23 changes: 23 additions & 0 deletions src/webviews/confirmationViewController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.md in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { type ConfirmationViewProperty } from "@microsoft/vscode-azext-utils";
import { ViewColumn } from "vscode";
import { ext } from "../extensionVariables";
import { WebviewController } from "./extension-server/WebviewController";

export type ConfirmationViewControllerType = {
title: string;
tabTitle: string;
description: string;
commandName: string; // only used to help construct the copilot prompt
items: Array<ConfirmationViewProperty>
}

export class ConfirmationViewController extends WebviewController<ConfirmationViewControllerType> {
constructor(viewConfig: ConfirmationViewControllerType) {
super(ext.context, viewConfig.tabTitle, 'confirmationView', viewConfig, ViewColumn.Active);
}
}
29 changes: 29 additions & 0 deletions src/webviews/webview-client/useConfiguration.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { useState } from 'react';

declare global {
interface Window {
config?: {
__initialData?: string;
[key: string]: unknown; // Optional: Allows any other properties in config
};
}
}

/**
* Use this hook to access the configuration object that was passed to the webview at its creation.W
*
* @returns The configuration object that was passed to the webview at its creation
*/
export function useConfiguration<T>(): T {
const [configuration] = useState<T>(() => {
const configString = decodeURIComponent(window.config?.__initialData ?? '{}');
return JSON.parse(configString) as T;
});

return configuration;
}
6 changes: 1 addition & 5 deletions test/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,7 @@ export async function run(): Promise<void> {

const mocha = new Mocha(options);

const files: string[] = await new Promise((resolve, reject) => {
glob('**/**.test.js', { cwd: __dirname }, (err, result) => {
err ? reject(err) : resolve(result);
});
});
const files: string[] = await glob.glob('**/**.test.js', { cwd: __dirname });

files.forEach(f => mocha.addFile(path.resolve(__dirname, f)));

Expand Down
68 changes: 68 additions & 0 deletions test/ui-tests/confirmationView.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License", destination); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import * as assert from 'assert';
import { readFileSync } from 'fs';
import { join } from 'path';
import { ActivityBar, type ExtensionsViewItem, type ExtensionsViewSection } from 'vscode-extension-tester';

function getPackageJson(): any {
// get the content of the current project's package.json
const packageJsonPath = join(__dirname, '..', '..', 'package.json');
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
return packageJson;
}

// sample test code on how to look for an extension
describe('Example extension view tests', () => {
let helloExtension: ExtensionsViewItem;

before(async function () {
this.timeout(15000);
// open the extensions view
const view = await (await new ActivityBar().getViewControl('Extensions'))?.openView();
await view?.getDriver().wait(async function () {
return (await view.getContent().getSections()).length > 0;
});

// we want to find the hello-world extension (this project)
// first we need a view section, best place to get started is the 'Installed' section
const extensions = (await view?.getContent().getSection('Installed')) as ExtensionsViewSection;

const packageJson = getPackageJson();

// search for the extension, you can use any syntax vscode supports for the search field
// it is best to prepend @installed to the extension name if you don't want to see the results from marketplace
// also, getting the name directly from package.json seem like a good idea
await extensions.getDriver().wait(async function () {
helloExtension = (await extensions.findItem(`@installed ${packageJson.displayName}`)) as ExtensionsViewItem;
return helloExtension !== undefined;
});
});

it('Check the extension info', async () => {
// now we have the extension item, we can check it shows all the fields we want
const author = await helloExtension.getAuthor();
const version = await helloExtension.getVersion();

const packageJson = getPackageJson();

// in this case we are comparing the results against the values in package.json
assert.equal(author, packageJson.publisher);
assert.equal(version, packageJson.version);
});
});
68 changes: 68 additions & 0 deletions test/ui-tests/helloWorld.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License", destination); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import * as assert from 'assert';
import { readFileSync } from 'fs';
import { join } from 'path';
import { ActivityBar, type ExtensionsViewItem, type ExtensionsViewSection } from 'vscode-extension-tester';

function getPackageJson(): any {
// get the content of the current project's package.json
const packageJsonPath = join(__dirname, '..', '..', 'package.json');
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
return packageJson;
}

// sample test code on how to look for an extension
describe('Example extension view tests', () => {
let helloExtension: ExtensionsViewItem;

before(async function () {
this.timeout(15000);
// open the extensions view
const view = await (await new ActivityBar().getViewControl('Extensions'))?.openView();
await view?.getDriver().wait(async function () {
return (await view.getContent().getSections()).length > 0;
});

// we want to find the hello-world extension (this project)
// first we need a view section, best place to get started is the 'Installed' section
const extensions = (await view?.getContent().getSection('Installed')) as ExtensionsViewSection;

const packageJson = getPackageJson();

// search for the extension, you can use any syntax vscode supports for the search field
// it is best to prepend @installed to the extension name if you don't want to see the results from marketplace
// also, getting the name directly from package.json seem like a good idea
await extensions.getDriver().wait(async function () {
helloExtension = (await extensions.findItem(`@installed ${packageJson.displayName}`)) as ExtensionsViewItem;
return helloExtension !== undefined;
});
});

it('Check the extension info', async () => {
// now we have the extension item, we can check it shows all the fields we want
const author = await helloExtension.getAuthor();
const version = await helloExtension.getVersion();

const packageJson = getPackageJson();

// in this case we are comparing the results against the values in package.json
assert.equal(author, packageJson.publisher);
assert.equal(version, packageJson.version);
});
});
1 change: 1 addition & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"skipLibCheck": true,
"strictNullChecks": true,
"noUnusedParameters": true,
"resolveJsonModule": true,
"baseUrl": "./",
"paths": {
"*": [
Expand Down
20 changes: 17 additions & 3 deletions webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,30 @@ let webConfig = dev.getDefaultWebpackConfig({
'../build/default/bufferutil': 'commonjs ../build/default/bufferutil',
},
target: 'webworker',
plugins: [new webpack.ProvidePlugin({
Buffer: ['buffer', 'Buffer'],
})],
plugins: [
new webpack.ProvidePlugin({
Buffer: ['buffer', 'Buffer'],
}),
new webpack.ProvidePlugin({
process: 'process/browser',
})
],
suppressCleanDistFolder: true,
resolveFallbackAliases: {
'constants': false
},
alias
});

// Add process polyfill and alias for browser builds
webConfig.resolve = webConfig.resolve || {};
webConfig.resolve.fallback = Object.assign({}, webConfig.resolve.fallback, {
process: require.resolve('process/browser.js')
});
webConfig.resolve.alias = Object.assign({}, webConfig.resolve.alias, {
'process/browser': require.resolve('process/browser.js')
});

if (DEBUG_WEBPACK) {
console.log('Config:', nodeConfig);
}
Expand Down
1 change: 1 addition & 0 deletions webpack.config.views.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#!/usr/bin/env node
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
Expand Down
Loading