Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added E2E execution plan tests with coverage #18929

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open
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
17 changes: 9 additions & 8 deletions .github/workflows/daily-build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,12 @@ jobs:
PROFILE_NAME=test-server
DISPLAY=:10 yarn smoketest

- name: Smoke Test Report
uses: dorny/test-reporter@v1
if: success() || failure()
with:
name: 'Smoke Test Report'
path: ./test-reports/**/smoke-results.xml
reporter: jest-junit
badge-title: 'smoke-tests'
# Comment out smoke test report until new smoke tests are integrated
# - name: Smoke Test Report
# uses: dorny/test-reporter@v1
# if: success() || failure()
# with:
# name: 'Smoke Test Report'
# path: ./test-reports/**/smoke-results.xml
# reporter: jest-junit
# badge-title: 'smoke-tests'
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,6 @@ package.nls.*.json
webviews-metafile.json
# Ignore all l10n files except the default one (bundle.l10n.json)
/localization/l10n/bundle.l10n.*.json
.eslintcache
.eslintcache
.nyc_output
/test/resources/screenshots
4 changes: 3 additions & 1 deletion .vscodeignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,6 @@ tslint*.json
**/*.ts
webviews-metafile.json
images/ux
FEATURES.md
FEATURES.md
.nyc_output
/test/resources/screenshots
2 changes: 1 addition & 1 deletion gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,7 @@ gulp.task('ext:test', async () => {
});
});

gulp.task('ext:smoke', run('npx playwright test'));
gulp.task('ext:smoke', run('echo TBD'));

gulp.task('test', gulp.series('ext:test'));

Expand Down
54 changes: 33 additions & 21 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@
"@types/vscode-webview": "^1.57.5",
"@typescript-eslint/eslint-plugin": "^8.7.0",
"@typescript-eslint/parser": "^8.7.0",
"@vitejs/plugin-react": "^4.3.4",
"@vscode/l10n": "^0.0.18",
"@vscode/l10n-dev": "^0.0.35",
"@vscode/test-cli": "^0.0.10",
Expand Down Expand Up @@ -171,6 +172,8 @@
"typescript": "^5.6.2",
"typescript-eslint": "^8.7.0",
"uglify-js": "mishoo/UglifyJS2#harmony-v2.8.22",
"vite": "^6.2.0",
"vite-plugin-istanbul": "^7.0.0",
"vscode-nls-dev": "2.0.1",
"xliff": "^6.2.1",
"yargs": "^17.7.2"
Expand Down Expand Up @@ -925,9 +928,9 @@
}
},
{
"command": "mssql.enableRichExperiences",
"title": "%mssql.enableRichExperiences%",
"category": "MS SQL"
"command": "mssql.enableRichExperiences",
"title": "%mssql.enableRichExperiences%",
"category": "MS SQL"
}
],
"keybindings": [
Expand Down Expand Up @@ -1050,15 +1053,24 @@
"description": "%mssql.connectionGroup.id%"
},
"color": {
"type": ["string", null],
"type": [
"string",
null
],
"description": "%mssql.connectionGroup.color%"
},
"description": {
"type": ["string", null],
"type": [
"string",
null
],
"description": "%mssql.connectionGroup.description%"
},
"parentId": {
"type": ["string", null],
"type": [
"string",
null
],
"description": "%mssql.connectionGroup.parentId%"
}
}
Expand Down Expand Up @@ -1289,20 +1301,20 @@
"scope": "resource"
},
"mssql.resultsFontFamily": {
"type": "string",
"description": "%mssql.resultsFontFamily%",
"default": null,
"scope": "resource"
"type": "string",
"description": "%mssql.resultsFontFamily%",
"default": null,
"scope": "resource"
},
"mssql.resultsFontSize": {
"type": [
"number",
"null"
],
"maximum": 24,
"description": "%mssql.resultsFontSize%",
"default": null,
"scope": "resource"
"type": [
"number",
"null"
],
"maximum": 24,
"description": "%mssql.resultsFontSize%",
"default": null,
"scope": "resource"
},
"mssql.saveAsCsv.includeHeaders": {
"type": "boolean",
Expand Down Expand Up @@ -1497,9 +1509,9 @@
"description": "%mssql.logFilesRemovalLimit%"
},
"mssql.resultsGrid.autoSizeColumns": {
"type": "boolean",
"default": true,
"description": "%mssql.resultsGrid.autoSizeColumns%"
"type": "boolean",
"default": true,
"description": "%mssql.resultsGrid.autoSizeColumns%"
},
"mssql.query.displayBitAsNumber": {
"type": "boolean",
Expand Down
72 changes: 46 additions & 26 deletions playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import dotenv from 'dotenv';
import { defineConfig } from '@playwright/test';
import dotenv from "dotenv";
import { defineConfig } from "@playwright/test";

dotenv.config({ path: './test/e2e/.env' });
dotenv.config({ path: "./test/e2e/.env" });

/**
* Read environment variables from file.
Expand All @@ -19,28 +19,48 @@ dotenv.config({ path: './test/e2e/.env' });
* See https://playwright.dev/docs/test-configuration.
*/
export default defineConfig({
testDir: './test/e2e',
/* Run tests in files in parallel */
fullyParallel: false,
/* Fail the build on CI if you accidentally left test.only in the source code. */
forbidOnly: !!process.env.CI,
/* Retry on CI only */
retries: process.env.CI ? 2 : 0,
/* Opt out of parallel tests on CI. */
workers: 1,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: [['junit', {
outputFile: './test-reports/smoke-results.xml',
}]],
/* Set timeout to 5 minutes */
timeout: 5 * 60 * 1000,
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
/* Base URL to use in actions like `await page.goto('/')`. */
// baseURL: 'http://127.0.0.1:3000',
testDir: "./test/e2e",
testIgnore: ["oldUiTests/**"], // tests are old and do not work
testMatch: ["**/*.spec.ts"],
// Single template for all assertions
snapshotPathTemplate: './test/resources/screenshots/{testFilePath}/{arg}{ext}',
// Assertion-specific templates
expect: {
toHaveScreenshot: {
maxDiffPixelRatio: 0.02
}
},
/* Run tests in files in parallel */
fullyParallel: false,
/* Fail the build on CI if you accidentally left test.only in the source code. */
forbidOnly: !!process.env.CI,
/* Retry on CI only */
retries: process.env.CI ? 2 : 0,
/* Opt out of parallel tests on CI. */
workers: 1,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: [
[
"junit",
{
outputFile: "./test-reports/smoke-results.xml",
},
],
],
/* Set timeout to 5 minutes */
timeout: 5 * 60 * 1000,
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
/* Base URL to use in actions like `await page.goto('/')`. */
// baseURL: 'http://127.0.0.1:3000',

/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: 'on-first-retry',
video: 'retain-on-failure',
},
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: "on-first-retry",
video: "retain-on-failure",

// If using a browser context, ensure scripts load correctly
contextOptions: {
javaScriptEnabled: true,
},
},
});
2 changes: 1 addition & 1 deletion src/controllers/sharedExecutionPlanUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export async function saveExecutionPlan(
const saveUri = await vscode.window.showSaveDialog({
defaultUri: await getUniqueFilePath(folder, `plan`, sqlPlanLanguageId),
filters: {
[executionPlanFileFilter]: [`.${sqlPlanLanguageId}`],
[executionPlanFileFilter]: [`${sqlPlanLanguageId}`],
},
});

Expand Down
16 changes: 16 additions & 0 deletions src/reactviews/pages/ExecutionPlan/executionPlanGraph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ export const ExecutionPlanGraph: React.FC<ExecutionPlanGraphProps> = ({
const [propertiesWidth, setPropertiesWidth] = useState(400);
const [containerHeight, setContainerHeight] = useState("100%");
const resizableRef = useRef<HTMLDivElement>(null);
const inputRef = useRef<any | null>(null);

useEffect(() => {
if (!executionPlanState || isExecutionPlanLoaded) return;
Expand Down Expand Up @@ -202,6 +203,17 @@ export const ExecutionPlanGraph: React.FC<ExecutionPlanGraphProps> = ({
loadExecutionPlan();
}, [executionPlanState]);

useEffect(() => {
if (inputRef && inputRef.current) {
inputRef.current.focus();
}
}, [
customZoomClicked,
findNodeClicked,
highlightOpsClicked,
propertiesClicked,
]);

const handleCustomZoomInput = async () => {
if (executionPlanView) {
executionPlanView.setZoomLevel(zoomNumber);
Expand Down Expand Up @@ -290,6 +302,7 @@ export const ExecutionPlanGraph: React.FC<ExecutionPlanGraphProps> = ({
tabIndex={0}
>
<Input
ref={inputRef}
id="customZoomInputBox"
type="number"
size="small"
Expand Down Expand Up @@ -341,6 +354,7 @@ export const ExecutionPlanGraph: React.FC<ExecutionPlanGraphProps> = ({
setExecutionPlanView={setExecutionPlanView}
findNodeOptions={findNodeOptions}
setFindNodeClicked={setFindNodeClicked}
inputRef={inputRef}
/>
</div>
</Popover>
Expand All @@ -351,6 +365,7 @@ export const ExecutionPlanGraph: React.FC<ExecutionPlanGraphProps> = ({
executionPlanView={executionPlanView!}
setExecutionPlanView={setExecutionPlanView}
setHighlightOpsClicked={setHighlightOpsClicked}
inputRef={inputRef}
/>
</div>
</Popover>
Expand All @@ -370,6 +385,7 @@ export const ExecutionPlanGraph: React.FC<ExecutionPlanGraphProps> = ({
// guaranteed to be non-null
executionPlanView={executionPlanView!}
setPropertiesClicked={setPropertiesClicked}
inputRef={inputRef}
/>
</div>
</Popover>
Expand Down
3 changes: 3 additions & 0 deletions src/reactviews/pages/ExecutionPlan/findNodes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,15 @@ interface FindNodeProps {
setExecutionPlanView: any;
findNodeOptions: string[];
setFindNodeClicked: any;
inputRef: any;
}

export const FindNode: React.FC<FindNodeProps> = ({
executionPlanView,
setExecutionPlanView,
findNodeOptions,
setFindNodeClicked,
inputRef,
}) => {
const classes = useStyles();
const findNodeComparisonOptions: string[] = [
Expand Down Expand Up @@ -165,6 +167,7 @@ export const FindNode: React.FC<FindNodeProps> = ({
setFindNodeResultsIndex(-1);
setFindNodeResults([]);
}}
ref={inputRef}
>
{findNodeOptions.map((option) => (
<Option key={option} className={classes.option}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,17 @@ interface HighlightExpensiveOperationsProps {
executionPlanView: ExecutionPlanView;
setExecutionPlanView: any;
setHighlightOpsClicked: any;
inputRef: any;
}

export const HighlightExpensiveOperations: React.FC<
HighlightExpensiveOperationsProps
> = ({ executionPlanView, setExecutionPlanView, setHighlightOpsClicked }) => {
> = ({
executionPlanView,
setExecutionPlanView,
setHighlightOpsClicked,
inputRef,
}) => {
const classes = useStyles();
const [highlightMetricSelected, setHighlightMetricSelected] = useState("");

Expand Down Expand Up @@ -104,6 +110,14 @@ export const HighlightExpensiveOperations: React.FC<
setHighlightOpsClicked(false);
};

const handleKeyDownOnAccept = (
event: React.KeyboardEvent<HTMLButtonElement>,
) => {
if (event.key === "ArrowLeft") {
inputRef.current?.focus(); // Move focus to the combobox
}
};

return (
<div
id="highlightExpensiveOpsContainer"
Expand All @@ -122,6 +136,7 @@ export const HighlightExpensiveOperations: React.FC<
onOptionSelect={(_, data) =>
setHighlightMetricSelected(data.optionText ?? "")
}
ref={inputRef}
>
{highlightMetricOptions.map((option) => (
<Option key={option}>{option}</Option>
Expand All @@ -135,6 +150,7 @@ export const HighlightExpensiveOperations: React.FC<
title={locConstants.common.apply}
aria-label={locConstants.common.apply}
icon={<Checkmark20Regular />}
onKeyDown={handleKeyDownOnAccept}
/>
<Button
icon={<Dismiss20Regular />}
Expand Down
Loading
Loading