Skip to content

Commit d0ef39c

Browse files
authored
feat: release query settings dialog (and ci test reports) (#1101)
1 parent f1d7e13 commit d0ef39c

File tree

20 files changed

+603
-314
lines changed

20 files changed

+603
-314
lines changed

.github/workflows/ci.yml

+134-2
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ jobs:
3737
e2e_tests:
3838
name: Playwright Tests
3939
runs-on: ubuntu-latest
40+
permissions:
41+
contents: write
42+
pull-requests: write
43+
pages: write
4044

4145
services:
4246
backend:
@@ -50,16 +54,144 @@ jobs:
5054
- uses: actions/checkout@v4
5155
with:
5256
fetch-depth: 0
53-
- uses: actions/setup-node@v4
57+
58+
- name: Setup Node.js
59+
uses: actions/setup-node@v4
5460
with:
5561
node-version: 18
5662
cache: npm
5763

5864
- name: Install dependencies
5965
run: npm ci
6066

61-
- name: Install Plawright deps
67+
- name: Install Playwright deps
6268
run: npm run test:e2e:install
6369

6470
- name: Run Playwright tests
71+
id: run_tests
6572
run: npm run test:e2e
73+
env:
74+
CI: true
75+
PLAYWRIGHT_VIDEO: 'on'
76+
77+
- name: Upload Playwright artifacts
78+
if: always()
79+
uses: actions/upload-artifact@v3
80+
with:
81+
name: playwright-artifacts
82+
path: playwright-artifacts
83+
retention-days: 5
84+
85+
- name: Setup Pages
86+
if: always()
87+
uses: actions/configure-pages@v3
88+
89+
- name: Deploy report to GitHub Pages
90+
if: always()
91+
uses: peaceiris/actions-gh-pages@v3
92+
with:
93+
github_token: ${{ secrets.GITHUB_TOKEN }}
94+
publish_dir: ./playwright-artifacts/playwright-report
95+
destination_dir: ${{ github.event.pull_request.number }}
96+
97+
- name: Get test results
98+
if: always()
99+
id: test-results
100+
run: |
101+
echo "Current directory: $(pwd)"
102+
echo "Listing playwright-artifacts directory:"
103+
ls -R playwright-artifacts
104+
105+
if [ -f "playwright-artifacts/test-results.json" ]; then
106+
echo "Parsing JSON file:"
107+
total=$(jq '.stats.expected + .stats.unexpected + .stats.skipped' playwright-artifacts/test-results.json)
108+
passed=$(jq '.stats.expected' playwright-artifacts/test-results.json)
109+
failed=$(jq '.stats.unexpected' playwright-artifacts/test-results.json)
110+
skipped=$(jq '.stats.skipped' playwright-artifacts/test-results.json)
111+
112+
echo "Parsed values:"
113+
echo "Total: $total"
114+
echo "Passed: $passed"
115+
echo "Failed: $failed"
116+
echo "Skipped: $skipped"
117+
else
118+
echo "test-results.json file not found"
119+
total=0
120+
passed=0
121+
failed=0
122+
skipped=0
123+
fi
124+
125+
echo "total=$total" >> $GITHUB_OUTPUT
126+
echo "passed=$passed" >> $GITHUB_OUTPUT
127+
echo "failed=$failed" >> $GITHUB_OUTPUT
128+
echo "skipped=$skipped" >> $GITHUB_OUTPUT
129+
130+
- name: Update PR description
131+
if: always()
132+
uses: actions/github-script@v6
133+
with:
134+
github-token: ${{secrets.GITHUB_TOKEN}}
135+
script: |
136+
const reportUrl = `https://${context.repo.owner}.github.io/${context.repo.repo}/${context.issue.number}/`;
137+
const testResults = {
138+
total: ${{ steps.test-results.outputs.total || 0 }},
139+
passed: ${{ steps.test-results.outputs.passed || 0 }},
140+
failed: ${{ steps.test-results.outputs.failed || 0 }},
141+
skipped: ${{ steps.test-results.outputs.skipped || 0 }}
142+
};
143+
const status = testResults.failed > 0 ? '❌ FAILED' : '✅ PASSED';
144+
const statusColor = testResults.failed > 0 ? 'red' : 'green';
145+
146+
const testResultsSection = `## Playwright Test Results
147+
148+
**Status**: <span style="color: ${statusColor}; font-weight: bold;">${status}</span>
149+
150+
| Total | Passed | Failed | Skipped |
151+
|-------|--------|--------|---------|
152+
| ${testResults.total} | ${testResults.passed} | ${testResults.failed} | ${testResults.skipped} |
153+
154+
### 📊 Test Report
155+
156+
For detailed results, please check the [Playwright Report](${reportUrl})
157+
158+
### 🎥 Test Recordings
159+
160+
Video recordings of failed tests (if any) are available in the report.
161+
162+
---
163+
164+
<details>
165+
<summary>ℹ️ How to use this report</summary>
166+
167+
1. Click on the "Playwright Report" link above to view the full test results.
168+
2. In the report, you can see a breakdown of all tests, including any failures.
169+
3. For failed tests, you can view screenshots and video recordings to help debug the issues.
170+
4. Use the filters in the report to focus on specific test statuses or suites.
171+
172+
</details>`;
173+
174+
const { data: pullRequest } = await github.rest.pulls.get({
175+
owner: context.repo.owner,
176+
repo: context.repo.repo,
177+
pull_number: context.issue.number,
178+
});
179+
180+
const currentBody = pullRequest.body || '';
181+
const testResultsRegex = /## Playwright Test Results[\s\S]*?(?=\n## |$)/;
182+
183+
let newBody;
184+
if (testResultsRegex.test(currentBody)) {
185+
// If the section exists, replace it
186+
newBody = currentBody.replace(testResultsRegex, testResultsSection);
187+
} else {
188+
// If the section doesn't exist, add it to the end
189+
newBody = currentBody + '\n\n' + testResultsSection;
190+
}
191+
192+
await github.rest.pulls.update({
193+
owner: context.repo.owner,
194+
repo: context.repo.repo,
195+
pull_number: context.issue.number,
196+
body: newBody,
197+
});

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
# testing
99
/coverage
10+
playwright-artifacts
1011

1112
# production
1213
/build

playwright.config.ts

+9
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ const baseUrl = process.env.PLAYWRIGHT_BASE_URL;
66
const config: PlaywrightTestConfig = {
77
testDir: 'tests/suites',
88
timeout: 2 * 60 * 1000,
9+
outputDir: './playwright-artifacts/test-results',
10+
reporter: [
11+
['html', {outputFolder: './playwright-artifacts/playwright-report'}],
12+
['json', {outputFile: './playwright-artifacts/test-results.json'}],
13+
],
14+
915
// If there is no url provided, playwright starts webServer with the app in dev mode
1016
webServer: baseUrl
1117
? undefined
@@ -16,6 +22,9 @@ const config: PlaywrightTestConfig = {
1622
use: {
1723
baseURL: baseUrl || 'http://localhost:3000/',
1824
testIdAttribute: 'data-qa',
25+
trace: 'on-first-retry',
26+
video: 'retain-on-failure',
27+
screenshot: 'only-on-failure',
1928
},
2029
projects: [
2130
{

src/components/QueryExecutionStatus/QueryExecutionStatus.tsx

+1-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import {Icon, Tooltip} from '@gravity-ui/uikit';
55
import {isAxiosError} from 'axios';
66

77
import i18n from '../../containers/Tenant/Query/i18n';
8-
import {QUERY_SETTINGS, useSetting} from '../../lib';
98
import {cn} from '../../utils/cn';
109
import {useChangedQuerySettings} from '../../utils/hooks/useChangedQuerySettings';
1110
import QuerySettingsDescription from '../QuerySettingsDescription/QuerySettingsDescription';
@@ -20,10 +19,9 @@ interface QueryExecutionStatusProps {
2019
}
2120

2221
const QuerySettingsIndicator = () => {
23-
const [useQuerySettings] = useSetting<boolean>(QUERY_SETTINGS);
2422
const {isIndicatorShown, changedLastExecutionSettingsDescriptions} = useChangedQuerySettings();
2523

26-
if (!isIndicatorShown || !useQuerySettings) {
24+
if (!isIndicatorShown) {
2725
return null;
2826
}
2927

src/containers/Authentication/Authentication.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ function Authentication({closable = false}: AuthenticationProps) {
9090
<Icon data={ydbLogoIcon} size={24} />
9191
YDB
9292
</div>
93-
<ExternalLink href="http://ydb.tech/docs" target="_blank">
93+
<ExternalLink href="https://ydb.tech/docs" target="_blank">
9494
Documentation
9595
</ExternalLink>
9696
</div>

src/containers/Tenant/Query/ExecuteResult/ExecuteResult.tsx

+2-4
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,13 @@ import Fullscreen from '../../../../components/Fullscreen/Fullscreen';
1111
import {YDBGraph} from '../../../../components/Graph/Graph';
1212
import {QueryExecutionStatus} from '../../../../components/QueryExecutionStatus';
1313
import {QueryResultTable} from '../../../../components/QueryResultTable/QueryResultTable';
14-
import {QUERY_SETTINGS} from '../../../../lib';
1514
import {disableFullscreen} from '../../../../store/reducers/fullscreen';
1615
import type {ColumnType, KeyValueRow} from '../../../../types/api/query';
1716
import type {ValueOf} from '../../../../types/common';
1817
import type {IQueryResult} from '../../../../types/store/query';
1918
import {getArray} from '../../../../utils';
2019
import {cn} from '../../../../utils/cn';
21-
import {useSetting, useTypedDispatch} from '../../../../utils/hooks';
20+
import {useTypedDispatch} from '../../../../utils/hooks';
2221
import {parseQueryError} from '../../../../utils/query';
2322
import {PaneVisibilityToggleButtons} from '../../utils/paneVisibilityToggleHelpers';
2423
import {SimplifiedPlan} from '../ExplainResult/components/SimplifiedPlan/SimplifiedPlan';
@@ -63,7 +62,6 @@ export function ExecuteResult({
6362
const [selectedResultSet, setSelectedResultSet] = React.useState(0);
6463
const [activeSection, setActiveSection] = React.useState<SectionID>(resultOptionsIds.result);
6564
const dispatch = useTypedDispatch();
66-
const [useQuerySettings] = useSetting<boolean>(QUERY_SETTINGS);
6765

6866
const stats = data?.stats;
6967
const resultsSetsCount = data?.resultSets?.length;
@@ -237,7 +235,7 @@ export function ExecuteResult({
237235
/>
238236
</div>
239237
</div>
240-
{useQuerySettings && <QuerySettingsBanner />}
238+
<QuerySettingsBanner />
241239
<Fullscreen>{renderResultSection()}</Fullscreen>
242240
</React.Fragment>
243241
);

src/containers/Tenant/Query/ExplainResult/ExplainResult.tsx

+2-5
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,11 @@ import EnableFullscreenButton from '../../../../components/EnableFullscreenButto
77
import Fullscreen from '../../../../components/Fullscreen/Fullscreen';
88
import {LoaderWrapper} from '../../../../components/LoaderWrapper/LoaderWrapper';
99
import {QueryExecutionStatus} from '../../../../components/QueryExecutionStatus';
10-
import {QUERY_SETTINGS} from '../../../../lib';
1110
import type {PreparedExplainResponse} from '../../../../store/reducers/explainQuery/types';
1211
import {disableFullscreen} from '../../../../store/reducers/fullscreen';
1312
import type {ValueOf} from '../../../../types/common';
1413
import {cn} from '../../../../utils/cn';
15-
import {useSetting, useTypedDispatch} from '../../../../utils/hooks';
14+
import {useTypedDispatch} from '../../../../utils/hooks';
1615
import {parseQueryErrorToString} from '../../../../utils/query';
1716
import {PaneVisibilityToggleButtons} from '../../utils/paneVisibilityToggleHelpers';
1817
import {QuerySettingsBanner} from '../QuerySettingsBanner/QuerySettingsBanner';
@@ -82,8 +81,6 @@ export function ExplainResult({
8281
);
8382
const [isPending, startTransition] = React.useTransition();
8483

85-
const [useQuerySettings] = useSetting<boolean>(QUERY_SETTINGS);
86-
8784
React.useEffect(() => {
8885
return () => {
8986
dispatch(disableFullscreen());
@@ -167,7 +164,7 @@ export function ExplainResult({
167164
</React.Fragment>
168165
)}
169166
</div>
170-
{useQuerySettings && <QuerySettingsBanner />}
167+
<QuerySettingsBanner />
171168
<LoaderWrapper loading={loading || isPending}>
172169
<Fullscreen className={b('result')}>{renderContent()}</Fullscreen>
173170
</LoaderWrapper>

src/containers/Tenant/Query/QueriesHistory/QueriesHistory.tsx

+1-24
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,7 @@ import {TENANT_QUERY_TABS_ID} from '../../../../store/reducers/tenant/constants'
77
import {setQueryTab} from '../../../../store/reducers/tenant/tenant';
88
import type {QueryInHistory} from '../../../../types/store/executeQuery';
99
import {cn} from '../../../../utils/cn';
10-
import {
11-
useQueryExecutionSettings,
12-
useTypedDispatch,
13-
useTypedSelector,
14-
} from '../../../../utils/hooks';
15-
import {QUERY_MODES, QUERY_SYNTAX} from '../../../../utils/query';
10+
import {useTypedDispatch, useTypedSelector} from '../../../../utils/hooks';
1611
import {MAX_QUERY_HEIGHT, QUERY_TABLE_SETTINGS} from '../../utils/constants';
1712
import i18n from '../i18n';
1813

@@ -29,19 +24,10 @@ interface QueriesHistoryProps {
2924
function QueriesHistory({changeUserInput}: QueriesHistoryProps) {
3025
const dispatch = useTypedDispatch();
3126

32-
const [settings, setQuerySettings] = useQueryExecutionSettings();
33-
3427
const queriesHistory = useTypedSelector(selectQueriesHistory);
3528
const reversedHistory = [...queriesHistory].reverse();
3629

3730
const onQueryClick = (query: QueryInHistory) => {
38-
if (query.syntax === QUERY_SYNTAX.pg && settings.queryMode !== QUERY_MODES.pg) {
39-
setQuerySettings({...settings, queryMode: QUERY_MODES.pg});
40-
} else if (query.syntax !== QUERY_SYNTAX.pg && settings.queryMode === QUERY_MODES.pg) {
41-
// Set query mode for queries with yql syntax
42-
setQuerySettings({...settings, queryMode: QUERY_MODES.script});
43-
}
44-
4531
changeUserInput({input: query.queryText});
4632
dispatch(setQueryTab(TENANT_QUERY_TABS_ID.newQuery));
4733
};
@@ -60,15 +46,6 @@ function QueriesHistory({changeUserInput}: QueriesHistoryProps) {
6046
sortable: false,
6147
width: 600,
6248
},
63-
{
64-
name: 'syntax',
65-
header: 'Syntax',
66-
render: ({row}) => {
67-
return row.syntax === QUERY_SYNTAX.pg ? 'PostgreSQL' : 'YQL';
68-
},
69-
sortable: false,
70-
width: 200,
71-
},
7249
];
7350

7451
return (

0 commit comments

Comments
 (0)