Skip to content

Commit acf24fc

Browse files
attempt 8
1 parent 2fbfeb5 commit acf24fc

16 files changed

Lines changed: 686 additions & 451 deletions

File tree

.github/workflows/demos_visual_tests_frameworks.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -388,8 +388,7 @@ jobs:
388388
strategy:
389389
fail-fast: false
390390
matrix:
391-
# CONSTEL: [react(1/4), react(2/4), react(3/4), react(4/4), vue(1/4), vue(2/4), vue(3/4), vue(4/4), angular(1/4), angular(2/4), angular(3/4), angular(4/4)]
392-
CONSTEL: [react(1/6), react(2/6), react(3/6), react(4/6), react(5/6), react(6/6), vue(1/6), vue(2/6), vue(3/6), vue(4/6), vue(5/6), vue(6/6), angular(1/6), angular(2/6), angular(3/6), angular(4/6), angular(5/6), angular(6/6)]
391+
CONSTEL: [react(1/4), react(2/4), react(3/4), react(4/4), vue(1/4), vue(2/4), vue(3/4), vue(4/4), angular(1/4), angular(2/4), angular(3/4), angular(4/4)]
393392
# THEME: ['generic.light', 'material.blue.light', 'fluent.blue.light']
394393
THEME: ['fluent.blue.light']
395394

.github/workflows/qunit_tests-additional-renovation.yml

Lines changed: 29 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -81,12 +81,12 @@ jobs:
8181
fail-fast: false
8282
matrix:
8383
constel: [
84-
# 'misc(1/2)',
85-
# 'misc(2/2)',
86-
# 'ui.editors(1/2)',
87-
# 'ui.editors(2/2)',
88-
# 'ui.grid(1/2)',
89-
# 'ui.grid(2/2)',
84+
'misc(1/2)',
85+
'misc(2/2)',
86+
'ui.editors(1/2)',
87+
'ui.editors(2/2)',
88+
'ui.grid(1/2)',
89+
'ui.grid(2/2)',
9090
'ui.scheduler(1/3)',
9191
'ui.scheduler(2/3)',
9292
'ui.scheduler(3/3)'
@@ -141,45 +141,31 @@ jobs:
141141
matrix:
142142
constel: [
143143
'ui',
144-
# 'ui.widgets(1/3)',
145-
# 'ui.widgets(2/3)',
146-
# 'ui.widgets(3/3)',
147-
# 'ui.editors(1/2)',
148-
# 'ui.editors(2/2)',
149-
# 'ui.htmlEditor',
150-
# 'ui.grid(1/4)',
151-
# 'ui.grid(2/4)',
152-
# 'ui.grid(3/4)',
153-
# 'ui.grid(4/4)',
154-
# 'ui.scheduler(1/3)',
155-
# 'ui.scheduler(2/3)',
156-
# 'ui.scheduler(3/3)',
157-
'ui.widgets(1/2)',
158-
'ui.widgets(2/2)',
159-
# 'ui.widgets(3/3)',
160-
'ui.editors',
161-
# 'ui.editors(2/2)',
144+
'ui.widgets(1/3)',
145+
'ui.widgets(2/3)',
146+
'ui.widgets(3/3)',
147+
'ui.editors(1/2)',
148+
'ui.editors(2/2)',
162149
'ui.htmlEditor',
163-
'ui.grid(1/2)',
164-
'ui.grid(2/2)',
165-
# 'ui.grid(3/4)',
166-
# 'ui.grid(4/4)',
167-
'ui.scheduler(1/2)',
168-
'ui.scheduler(1/2)',
169-
# 'ui.scheduler(3/3)',
150+
'ui.grid(1/4)',
151+
'ui.grid(2/4)',
152+
'ui.grid(3/4)',
153+
'ui.grid(4/4)',
154+
'ui.scheduler(1/3)',
155+
'ui.scheduler(2/3)',
156+
'ui.scheduler(3/3)',
170157
'viz'
171158
]
172-
# kind: [ 'shadow-dom', 'ios10', 'android6' ]
173-
kind: [ 'shadow-dom' ]
159+
kind: [ 'shadow-dom', 'ios10', 'android6' ]
174160
include:
175161
- kind: 'shadow-dom'
176162
userAgent: ''
177163
useShadowDom: true
178-
# - kind: 'ios10'
179-
# userAgent: 'ios10'
180-
# - kind: 'android6'
181-
# userAgent: 'android6'
182-
# useJQuery: true
164+
- kind: 'ios10'
165+
userAgent: 'ios10'
166+
- kind: 'android6'
167+
userAgent: 'android6'
168+
useJQuery: true
183169

184170
steps:
185171
- name: Get sources
@@ -209,17 +195,17 @@ jobs:
209195
'export',
210196
'misc',
211197
'ui',
212-
# 'ui.editors(1/2)',
213-
# 'ui.editors(2/2)',
198+
'ui.editors(1/2)',
199+
'ui.editors(2/2)',
214200
'ui.editors',
215201
'ui.htmlEditor',
216202
'ui.grid(1/2)',
217203
'ui.grid(2/2)',
218204
# 7 minutes !!! (not so critical)
219205
# 'ui.grid',
220-
# 'ui.scheduler(1/3)',
221-
# 'ui.scheduler(2/3)',
222-
# 'ui.scheduler(3/3)',
206+
'ui.scheduler(1/3)',
207+
'ui.scheduler(2/3)',
208+
'ui.scheduler(3/3)',
223209
'ui.scheduler',
224210
'viz',
225211
'renovation'

apps/demos/testing/common.test.js

Lines changed: 82 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,21 @@ import { skippedTests } from './skipped-tests';
2424

2525
import { gitHubIgnored } from '../utils/visual-tests/github-ignored-list';
2626

27+
const formatTime = () => {
28+
const now = new Date();
29+
const h = String(now.getHours()).padStart(2, '0');
30+
const m = String(now.getMinutes()).padStart(2, '0');
31+
const s = String(now.getSeconds()).padStart(2, '0');
32+
const ms = String(now.getMilliseconds()).padStart(3, '0');
33+
return `[${h}:${m}:${s}.${ms}]`;
34+
};
35+
36+
const logWithTime = (message) => {
37+
console.log(`${formatTime()} ${message}`);
38+
};
39+
40+
const testAttempts = {};
41+
2742
const execCode = ClientFunction((code) => {
2843
// eslint-disable-next-line no-eval
2944
const result = eval(code);
@@ -62,10 +77,36 @@ FRAMEWORKS.forEach((approach) => {
6277
if (!shouldRunFramework(approach)) { return; }
6378
fixture(approach)
6479
.beforeEach(async (t) => {
80+
const testKey = `${approach}-${t.testRun.test.name}`;
81+
testAttempts[testKey] = (testAttempts[testKey] || 0) + 1;
82+
83+
logWithTime(`🔄 Attempt ${testAttempts[testKey]}: ${t.testRun.test.name} (${approach})`);
84+
6585
t.ctx.watchDogHandle = setTimeout(() => { throw new Error('test timeout exceeded'); }, 3 * 60 * 1000);
6686
await t.resizeWindow(1000, 800);
87+
t.ctx.testKey = testKey;
88+
})
89+
.afterEach(async (t) => {
90+
clearTimeout(t.ctx.watchDogHandle);
91+
92+
const testKey = t.ctx.testKey;
93+
const testName = t.testRun.test.name;
94+
const attempts = testAttempts[testKey];
95+
96+
if (t.testRun.errs && t.testRun.errs.length > 0) {
97+
// Test failed
98+
logWithTime(`❌ Test "${testName}" failed on attempt ${attempts}`);
99+
const errorMsg = t.testRun.errs[0].errMsg || t.testRun.errs[0].message || 'Unknown error';
100+
logWithTime(` Error: ${errorMsg}`);
101+
} else {
102+
// Test passed
103+
if (attempts > 1) {
104+
logWithTime(`✅ Test "${testName}" passed on attempt ${attempts}!`);
105+
} else {
106+
logWithTime(`✅ Test "${testName}" passed on first attempt`);
107+
}
108+
}
67109
})
68-
.afterEach((t) => clearTimeout(t.ctx.watchDogHandle))
69110
.clientScripts([
70111
{ module: 'mockdate' },
71112
// { module: 'axe-core/axe.min.js' },
@@ -124,6 +165,7 @@ FRAMEWORKS.forEach((approach) => {
124165
// pageURL = `http://127.0.0.1:808${getPortByIndex(index)}/Demos/${widgetName}/${demoName}/${approach}/?theme=dx.${theme}`;
125166
// } else {
126167
changeTheme(__dirname, `../${demoPath}/index.html`, process.env.THEME);
168+
console.log(`Running ${testName} ${approach} ${theme} at port ${getPortByIndex(index)}`);
127169
pageURL = `http://127.0.0.1:808${getPortByIndex(index)}/apps/demos/Demos/${widgetName}/${demoName}/${approach}/`;
128170
// }
129171
// // remove when tests enabled not only for datagrid
@@ -141,7 +183,9 @@ FRAMEWORKS.forEach((approach) => {
141183
skipJsErrorsComponents.includes(widgetName),
142184
)
143185
.clientScripts(clientScriptSource)(testName, async (t) => {
144-
console.time('Timer');
186+
const attemptInfo = t.ctx.currentAttempt ? ` (Attempt ${t.ctx.currentAttempt})` : '';
187+
logWithTime(`[TEST START${attemptInfo}] ${testName} - ${approach} - ${theme}`);
188+
console.time(`Timer-${testName}${attemptInfo}`);
145189

146190
if (visualTestStyles) {
147191
await execCode(visualTestStyles);
@@ -192,7 +236,42 @@ FRAMEWORKS.forEach((approach) => {
192236
await t.expect(comparisonResult).ok('INVALID_SCREENSHOT');
193237
}
194238

195-
console.timeEnd('Timer');
239+
const endAttemptInfo = t.ctx.currentAttempt ? ` (Attempt ${t.ctx.currentAttempt})` : '';
240+
logWithTime(`[TEST END${endAttemptInfo}] ${testName} - SUCCESS`);
241+
console.timeEnd(`Timer-${testName}${endAttemptInfo}`);
196242
});
197243
});
198244
});
245+
246+
// Test attempts statistics
247+
process.on('exit', () => {
248+
console.log('\n📊 TEST ATTEMPTS STATISTICS:');
249+
250+
const stats = { stable: 0, unstable: 0 };
251+
const unstableTests = [];
252+
253+
Object.entries(testAttempts).forEach(([testKey, attempts]) => {
254+
if (attempts === 1) {
255+
stats.stable++;
256+
} else if (attempts > 1) {
257+
stats.unstable++;
258+
unstableTests.push({ testKey, attempts });
259+
}
260+
});
261+
262+
if (unstableTests.length > 0) {
263+
console.log('\n⚠️ UNSTABLE TESTS:');
264+
unstableTests
265+
.sort((a, b) => b.attempts - a.attempts)
266+
.forEach(({ testKey, attempts }) => {
267+
console.log(` ${testKey}: ${attempts} attempts`);
268+
});
269+
}
270+
271+
console.log(`\n✅ Stable tests: ${stats.stable}`);
272+
console.log(`⚠️ Unstable tests: ${stats.unstable}`);
273+
274+
if (stats.unstable > 0) {
275+
console.log(`\n💡 Tip: Run with TCQUARANTINE=true for automatic retries`);
276+
}
277+
});

apps/demos/testing/widgets/common/EditorAppearanceVariants.test.js

Lines changed: 35 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -10,39 +10,39 @@ fixture('Common.EditorAppearanceVariants')
1010
});
1111

1212
runManualTest('Common', 'EditorAppearanceVariants', (test) => {
13-
// test('EditorAppearanceVariants', async (t) => {
14-
// const { takeScreenshot, compareResults } = createScreenshotsComparer(t);
15-
16-
// const SELECTBOX_CLASS = 'dx-selectbox';
17-
// const stylingModes = ['outlined', 'filled', 'underlined'];
18-
// const labelModes = ['static', 'floating', 'hidden', 'outside'];
19-
20-
// const clickSaveButton = async () => {
21-
// await t.click($('#validate'));
22-
// };
23-
24-
// const changeLabelMode = async (labelMode) => {
25-
// await t.click($(`.${SELECTBOX_CLASS}`).nth(1));
26-
// await t.click($('.dx-item').withText(labelMode));
27-
// };
28-
29-
// const changeStylingMode = async (stylingMode) => {
30-
// await t.click($(`.${SELECTBOX_CLASS}`).nth(0));
31-
// await t.click($('.dx-item').withText(stylingMode)).wait(500);
32-
// };
33-
34-
// await asyncForEach(stylingModes, async (stylingMode) => {
35-
// await asyncForEach(labelModes, async (labelMode) => {
36-
// await changeStylingMode(stylingMode);
37-
// await changeLabelMode(labelMode);
38-
// await clickSaveButton();
39-
40-
// await testScreenshot(t, takeScreenshot, `common_editor_appearance_variants_${stylingMode}_${labelMode}_desktop.png`);
41-
// });
42-
// });
43-
44-
// await t
45-
// .expect(compareResults.isValid())
46-
// .ok(compareResults.errorMessages());
47-
// });
13+
test('EditorAppearanceVariants', async (t) => {
14+
const { takeScreenshot, compareResults } = createScreenshotsComparer(t);
15+
16+
const SELECTBOX_CLASS = 'dx-selectbox';
17+
const stylingModes = ['outlined', 'filled', 'underlined'];
18+
const labelModes = ['static', 'floating', 'hidden', 'outside'];
19+
20+
const clickSaveButton = async () => {
21+
await t.click($('#validate'));
22+
};
23+
24+
const changeLabelMode = async (labelMode) => {
25+
await t.click($(`.${SELECTBOX_CLASS}`).nth(1));
26+
await t.click($('.dx-item').withText(labelMode));
27+
};
28+
29+
const changeStylingMode = async (stylingMode) => {
30+
await t.click($(`.${SELECTBOX_CLASS}`).nth(0));
31+
await t.click($('.dx-item').withText(stylingMode)).wait(500);
32+
};
33+
34+
await asyncForEach(stylingModes, async (stylingMode) => {
35+
await asyncForEach(labelModes, async (labelMode) => {
36+
await changeStylingMode(stylingMode);
37+
await changeLabelMode(labelMode);
38+
await clickSaveButton();
39+
40+
await testScreenshot(t, takeScreenshot, `common_editor_appearance_variants_${stylingMode}_${labelMode}_desktop.png`);
41+
});
42+
});
43+
44+
await t
45+
.expect(compareResults.isValid())
46+
.ok(compareResults.errorMessages());
47+
});
4848
});

0 commit comments

Comments
 (0)