editmode.test.ts 36 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184
  1. /**
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing,
  13. * software distributed under the License is distributed on an
  14. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  15. * KIND, either express or implied. See the License for the
  16. * specific language governing permissions and limitations
  17. * under the License.
  18. */
  19. import { SAMPLE_DASHBOARD_1, TABBED_DASHBOARD } from 'cypress/utils/urls';
  20. import {
  21. drag,
  22. resize,
  23. setSelectSearchInput,
  24. waitForChartLoad,
  25. } from 'cypress/utils';
  26. import { edit } from 'brace';
  27. import {
  28. interceptExploreUpdate,
  29. interceptGet,
  30. interceptUpdate,
  31. openTab,
  32. } from './utils';
  33. import {
  34. interceptV1ChartData,
  35. interceptFiltering as interceptCharts,
  36. } from '../explore/utils';
  37. function editDashboard() {
  38. cy.getBySel('edit-dashboard-button').click();
  39. }
  40. function openProperties() {
  41. cy.getBySel('actions-trigger').click({ force: true });
  42. cy.getBySel('header-actions-menu')
  43. .contains('Edit properties')
  44. .click({ force: true });
  45. cy.get('.ant-modal-body').should('be.visible');
  46. }
  47. function assertMetadata(text: string) {
  48. const regex = new RegExp(text);
  49. // Ensure the JSON metadata editor exists and is in view
  50. cy.get('#json_metadata').should('exist');
  51. cy.get('#json_metadata').scrollIntoView({ offset: { top: -100, left: 0 } });
  52. cy.wait(200); // Small wait for scroll
  53. cy.get('#json_metadata')
  54. .should('exist')
  55. .then(() => {
  56. const metadata = cy.$$('#json_metadata')[0];
  57. // cypress can read this locally, but not in ci
  58. // so we have to use the ace module directly to fetch the value
  59. expect(edit(metadata).getValue()).to.match(regex);
  60. });
  61. }
  62. function openAdvancedProperties() {
  63. // Scroll to Advanced Settings section first since modal content is scrollable
  64. cy.get('.ant-modal-body').contains('Advanced Settings').scrollIntoView();
  65. cy.get('.ant-modal-body')
  66. .contains('Advanced Settings')
  67. .should('be.visible')
  68. .click({ force: true });
  69. // Wait for the section to expand and the JSON metadata editor to be in DOM
  70. cy.get('#json_metadata').should('exist');
  71. // Scroll the JSON metadata editor into view within the modal body
  72. cy.get('#json_metadata').scrollIntoView({ offset: { top: -100, left: 0 } });
  73. // Wait a bit for the scroll to complete and element to be positioned
  74. cy.wait(500);
  75. // Check that it exists rather than visible due to CSS overflow issues
  76. cy.get('#json_metadata').should('exist');
  77. }
  78. function dragComponent(
  79. component = 'Unicode Cloud',
  80. target = 'card-title',
  81. withFiltering = true,
  82. ) {
  83. if (withFiltering) {
  84. cy.getBySel('dashboard-charts-filter-search-input').type(component, {
  85. force: true,
  86. });
  87. cy.wait('@filtering');
  88. }
  89. cy.wait(500);
  90. drag(`[data-test="${target}"]`, component).to(
  91. '[data-test="grid-content"] [data-test="dragdroppable-object"]',
  92. );
  93. }
  94. function discardChanges() {
  95. cy.getBySel('undo-action').click({ force: true });
  96. }
  97. function visitEdit(sampleDashboard = SAMPLE_DASHBOARD_1) {
  98. interceptCharts();
  99. interceptGet();
  100. if (sampleDashboard === SAMPLE_DASHBOARD_1) {
  101. cy.createSampleDashboards([0]);
  102. }
  103. cy.visit(sampleDashboard);
  104. cy.wait('@get');
  105. editDashboard();
  106. cy.get('.grid-container').should('exist');
  107. cy.wait('@filtering');
  108. cy.wait(500);
  109. }
  110. function visit(sampleDashboard = SAMPLE_DASHBOARD_1) {
  111. interceptCharts();
  112. interceptGet();
  113. if (sampleDashboard === SAMPLE_DASHBOARD_1) {
  114. cy.createSampleDashboards([0]);
  115. }
  116. cy.visit(sampleDashboard);
  117. cy.wait('@get');
  118. cy.get('.grid-container').should('exist');
  119. cy.wait(500);
  120. }
  121. function resetDashboardColors(dashboard = 'tabbed_dash') {
  122. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  123. cy.getDashboard(dashboard).then((r: Record<string, any>) => {
  124. const jsonMetadata = r?.json_metadata || '{}';
  125. const metadata = JSON.parse(jsonMetadata);
  126. const resetMetadata = JSON.stringify({
  127. ...metadata,
  128. color_scheme: '',
  129. label_colors: {},
  130. shared_label_colors: [],
  131. map_label_colors: {},
  132. });
  133. cy.updateDashboard(r.id, {
  134. certification_details: r.certification_details,
  135. certified_by: r.certified_by,
  136. css: r.css,
  137. dashboard_title: r.dashboard_title,
  138. json_metadata: resetMetadata,
  139. owners: r.owners,
  140. slug: r.slug,
  141. });
  142. });
  143. }
  144. function selectColorScheme(
  145. color: string,
  146. target = 'dashboard-edit-properties-form',
  147. ) {
  148. // First, expand the Styling section if it's collapsed
  149. cy.get(`[data-test="${target}"]`).within(() => {
  150. // Find the Collapse header that contains "Styling" text
  151. cy.contains('Styling').scrollIntoView();
  152. cy.contains('Styling')
  153. .closest('.ant-collapse-header')
  154. .then($header => {
  155. // Click to expand regardless of current state
  156. cy.wrap($header).click({ force: true });
  157. });
  158. // Wait for animation and verify section is expanded
  159. cy.contains('Styling')
  160. .closest('.ant-collapse-header')
  161. .should('have.attr', 'aria-expanded', 'true');
  162. cy.wait(500); // Extra wait for content to render
  163. // Ensure the color scheme input is visible before proceeding
  164. cy.get('input[aria-label="Select color scheme"]').should('be.visible');
  165. });
  166. // Now select the color scheme
  167. cy.get(`[data-test="${target}"] input[aria-label="Select color scheme"]`)
  168. .should('exist')
  169. .then($input => {
  170. setSelectSearchInput($input, color.slice(0, 5));
  171. });
  172. }
  173. function saveAndGo(dashboard = 'Tabbed Dashboard') {
  174. interceptExploreUpdate();
  175. cy.getBySel('query-save-button').click();
  176. cy.getBySel('save-modal-body').then($modal => {
  177. cy.wrap($modal)
  178. .find("div[aria-label='Select a dashboard'] .ant-select-selection-item")
  179. .should('have.text', dashboard);
  180. cy.getBySel('save-overwrite-radio').should('not.be.disabled');
  181. cy.getBySel('save-overwrite-radio').click();
  182. cy.get('#btn_modal_save_goto_dash').click();
  183. cy.wait('@chartUpdate');
  184. });
  185. }
  186. function applyChanges() {
  187. cy.getBySel('modal-confirm-button').click({ force: true });
  188. // Wait for modal to close completely
  189. cy.get('.ant-modal-wrap').should('not.exist');
  190. }
  191. function saveChanges() {
  192. interceptUpdate();
  193. cy.getBySel('header-save-button').click({ force: true });
  194. cy.wait('@update');
  195. }
  196. function clearMetadata() {
  197. // Ensure the JSON metadata editor exists and scroll it into view
  198. cy.get('#json_metadata').should('exist');
  199. cy.get('#json_metadata').scrollIntoView({ offset: { top: -100, left: 0 } });
  200. cy.wait(200); // Small wait for scroll
  201. cy.get('#json_metadata').then($jsonmetadata => {
  202. cy.wrap($jsonmetadata).find('.ace_content').click({ force: true });
  203. cy.wrap($jsonmetadata)
  204. .find('.ace_text-input')
  205. .then($ace => {
  206. cy.wrap($ace).focus();
  207. cy.wrap($ace).type('{selectall}', { force: true });
  208. cy.wrap($ace).type('{backspace}', { force: true });
  209. });
  210. });
  211. }
  212. function writeMetadata(metadata: string) {
  213. // Ensure the JSON metadata editor exists and scroll it into view
  214. cy.get('#json_metadata').should('exist');
  215. cy.get('#json_metadata').scrollIntoView({ offset: { top: -100, left: 0 } });
  216. cy.wait(200); // Small wait for scroll
  217. cy.get('#json_metadata').then($jsonmetadata => {
  218. cy.wrap($jsonmetadata).find('.ace_content').click({ force: true });
  219. cy.wrap($jsonmetadata)
  220. .find('.ace_text-input')
  221. .then($ace => {
  222. cy.wrap($ace).focus();
  223. cy.wrap($ace).type(metadata, {
  224. parseSpecialCharSequences: false,
  225. force: true,
  226. });
  227. });
  228. });
  229. }
  230. function openExploreWithDashboardContext(chartName: string) {
  231. interceptV1ChartData();
  232. interceptGet();
  233. cy.get(
  234. `[data-test-chart-name='${chartName}'] [aria-label='More Options']`,
  235. ).click();
  236. cy.get(`[data-test-edit-chart-name='${chartName}']`)
  237. .should('be.visible')
  238. .trigger('keydown', {
  239. keyCode: 13,
  240. which: 13,
  241. force: true,
  242. });
  243. cy.wait('@v1Data');
  244. cy.get('.chart-container').should('exist');
  245. }
  246. function saveExploreColorScheme(
  247. chart = 'Top 10 California Names Timeseries',
  248. colorScheme = 'supersetColors',
  249. ) {
  250. interceptExploreUpdate();
  251. openExploreWithDashboardContext(chart);
  252. openTab(0, 1, 'control-tabs');
  253. selectColorScheme(colorScheme, 'control-item');
  254. cy.getBySel('query-save-button').click();
  255. cy.getBySel('save-overwrite-radio').click();
  256. cy.getBySel('btn-modal-save').click();
  257. cy.wait('@chartUpdate');
  258. }
  259. // FIXME: Skipping some tests as ECharts are rendered using Canvas and we cannot inspect the elements
  260. // to verify the colors. We should revisit these tests once we have a solution to verify ECharts.
  261. describe('Dashboard edit', () => {
  262. describe('Color consistency', () => {
  263. beforeEach(() => {
  264. resetDashboardColors();
  265. });
  266. it.skip('should not allow to change color scheme of a chart when dashboard has one', () => {
  267. visitEdit(TABBED_DASHBOARD);
  268. openProperties();
  269. selectColorScheme('blueToGreen');
  270. applyChanges();
  271. saveChanges();
  272. // open nested tab
  273. openTab(1, 1);
  274. waitForChartLoad({
  275. name: 'Top 10 California Names Timeseries',
  276. viz: 'echarts_timeseries_line',
  277. });
  278. openExploreWithDashboardContext('Top 10 California Names Timeseries');
  279. // hover over canvas elements
  280. cy.get('canvas').trigger('mouseover', { force: true });
  281. // label Anthony
  282. cy.get('[data-test="chart-container"] .line .nv-legend-symbol')
  283. .first()
  284. .should('have.css', 'fill', 'rgb(50, 0, 167)');
  285. openTab(0, 1, 'control-tabs');
  286. // Expand Styling section first
  287. cy.contains('Styling').scrollIntoView();
  288. cy.contains('Styling').closest('.ant-collapse-header').click();
  289. cy.get('[aria-label="Select color scheme"]').should('be.disabled');
  290. });
  291. it.skip('should not allow to change color scheme of a chart when dashboard has no scheme but chart has shared labels', () => {
  292. visit(TABBED_DASHBOARD);
  293. // open nested tab
  294. openTab(1, 1);
  295. waitForChartLoad({
  296. name: 'Top 10 California Names Timeseries',
  297. viz: 'echarts_timeseries_line',
  298. });
  299. // open second top tab to catch shared labels
  300. openTab(0, 1);
  301. waitForChartLoad({
  302. name: 'Trends',
  303. viz: 'echarts_timeseries_line',
  304. });
  305. openTab(0, 0);
  306. openExploreWithDashboardContext('Top 10 California Names Timeseries');
  307. // label Anthony
  308. cy.get('[data-test="chart-container"] .line .nv-legend-symbol')
  309. .first()
  310. .should('have.css', 'fill', 'rgb(31, 168, 201)');
  311. openTab(0, 1, 'control-tabs');
  312. // Expand Styling section first
  313. cy.contains('Styling').scrollIntoView();
  314. cy.contains('Styling').closest('.ant-collapse-header').click();
  315. cy.get('[aria-label="Select color scheme"]').should('be.disabled');
  316. });
  317. it.skip('should allow to change color scheme of a chart when dashboard has no scheme but only custom label colors', () => {
  318. visitEdit(TABBED_DASHBOARD);
  319. openProperties();
  320. openAdvancedProperties();
  321. clearMetadata();
  322. writeMetadata('{"color_scheme":"","label_colors":{"Anthony":"red"}}');
  323. applyChanges();
  324. saveChanges();
  325. // open nested tab
  326. openTab(1, 1);
  327. waitForChartLoad({
  328. name: 'Top 10 California Names Timeseries',
  329. viz: 'echarts_timeseries_line',
  330. });
  331. // label Anthony
  332. cy.get(
  333. '[data-test-chart-name="Top 10 California Names Timeseries"] .line .nv-legend-symbol',
  334. )
  335. .first()
  336. .should('have.css', 'fill', 'rgb(255, 0, 0)');
  337. openExploreWithDashboardContext('Top 10 California Names Timeseries');
  338. // label Anthony
  339. cy.get('[data-test="chart-container"] .line .nv-legend-symbol')
  340. .first()
  341. .should('have.css', 'fill', 'rgb(255, 0, 0)');
  342. openTab(0, 1, 'control-tabs');
  343. selectColorScheme('blueToGreen', 'control-item');
  344. // label Anthony
  345. cy.get('[data-test="chart-container"] .line .nv-legend-symbol')
  346. .first()
  347. .should('have.css', 'fill', 'rgb(255, 0, 0)');
  348. // label Christopher
  349. cy.get('[data-test="chart-container"] .line .nv-legend-symbol')
  350. .eq(1)
  351. .should('have.css', 'fill', 'rgb(50, 0, 167)');
  352. // label Daniel
  353. cy.get('[data-test="chart-container"] .line .nv-legend-symbol')
  354. .eq(2)
  355. .should('have.css', 'fill', 'rgb(0, 76, 218)');
  356. // label David
  357. cy.get('[data-test="chart-container"] .line .nv-legend-symbol')
  358. .eq(3)
  359. .should('have.css', 'fill', 'rgb(0, 116, 241)');
  360. });
  361. it.skip('should allow to change color scheme of a chart when dashboard has no scheme and show the change', () => {
  362. visit(TABBED_DASHBOARD);
  363. // open nested tab
  364. openTab(1, 1);
  365. waitForChartLoad({
  366. name: 'Top 10 California Names Timeseries',
  367. viz: 'echarts_timeseries_line',
  368. });
  369. // label Anthony
  370. cy.get(
  371. '[data-test-chart-name="Top 10 California Names Timeseries"] .line .nv-legend-symbol',
  372. )
  373. .first()
  374. .should('have.css', 'fill', 'rgb(31, 168, 201)');
  375. openExploreWithDashboardContext('Top 10 California Names Timeseries');
  376. // label Anthony
  377. cy.get('[data-test="chart-container"] .line .nv-legend-symbol')
  378. .first()
  379. .should('have.css', 'fill', 'rgb(31, 168, 201)');
  380. openTab(0, 1, 'control-tabs');
  381. selectColorScheme('blueToGreen', 'control-item');
  382. // label Anthony
  383. cy.get('[data-test="chart-container"] .line .nv-legend-symbol')
  384. .first()
  385. .should('have.css', 'fill', 'rgb(50, 0, 167)');
  386. saveAndGo();
  387. // label Anthony
  388. cy.get('[data-test="chart-container"] .line .nv-legend-symbol')
  389. .first()
  390. .should('have.css', 'fill', 'rgb(50, 0, 167)');
  391. // reset original scheme
  392. saveExploreColorScheme();
  393. });
  394. it.skip('should allow to change color scheme of a chart when dashboard has no scheme but custom label colors and show the change', () => {
  395. visitEdit(TABBED_DASHBOARD);
  396. openProperties();
  397. openAdvancedProperties();
  398. clearMetadata();
  399. writeMetadata('{"color_scheme":"","label_colors":{"Anthony":"red"}}');
  400. applyChanges();
  401. saveChanges();
  402. // open nested tab
  403. openTab(1, 1);
  404. waitForChartLoad({
  405. name: 'Top 10 California Names Timeseries',
  406. viz: 'echarts_timeseries_line',
  407. });
  408. // label Anthony
  409. cy.get(
  410. '[data-test-chart-name="Top 10 California Names Timeseries"] .line .nv-legend-symbol',
  411. )
  412. .first()
  413. .should('have.css', 'fill', 'rgb(255, 0, 0)');
  414. openExploreWithDashboardContext('Top 10 California Names Timeseries');
  415. // label Anthony
  416. cy.get('[data-test="chart-container"] .line .nv-legend-symbol')
  417. .first()
  418. .should('have.css', 'fill', 'rgb(255, 0, 0)');
  419. openTab(0, 1, 'control-tabs');
  420. selectColorScheme('blueToGreen', 'control-item');
  421. // label Anthony
  422. cy.get('[data-test="chart-container"] .line .nv-legend-symbol')
  423. .first()
  424. .should('have.css', 'fill', 'rgb(255, 0, 0)');
  425. // label Christopher
  426. cy.get('[data-test="chart-container"] .line .nv-legend-symbol')
  427. .eq(1)
  428. .should('have.css', 'fill', 'rgb(50, 0, 167)');
  429. saveAndGo();
  430. // label Anthony
  431. cy.get('[data-test="chart-container"] .line .nv-legend-symbol')
  432. .first()
  433. .should('have.css', 'fill', 'rgb(255, 0, 0)');
  434. // label Christopher
  435. cy.get('[data-test="chart-container"] .line .nv-legend-symbol')
  436. .eq(1)
  437. .should('have.css', 'fill', 'rgb(50, 0, 167)');
  438. // reset original scheme
  439. saveExploreColorScheme();
  440. });
  441. it.skip('should not change colors on refreshes with no color scheme set', () => {
  442. visit(TABBED_DASHBOARD);
  443. // open nested tab
  444. openTab(1, 1);
  445. waitForChartLoad({
  446. name: 'Top 10 California Names Timeseries',
  447. viz: 'echarts_timeseries_line',
  448. });
  449. // label Anthony
  450. cy.get(
  451. '[data-test-chart-name="Top 10 California Names Timeseries"] .line .nv-legend-symbol',
  452. )
  453. .first()
  454. .should('have.css', 'fill', 'rgb(31, 168, 201)');
  455. // open 2nd main tab
  456. openTab(0, 1);
  457. waitForChartLoad({ name: 'Trends', viz: 'echarts_timeseries_line' });
  458. // label Andrew
  459. cy.get('[data-test-chart-name="Trends"] .line .nv-legend-symbol')
  460. .eq(1)
  461. .should('have.css', 'fill', 'rgb(69, 78, 124)');
  462. visit(TABBED_DASHBOARD);
  463. // open nested tab
  464. openTab(1, 1);
  465. waitForChartLoad({
  466. name: 'Top 10 California Names Timeseries',
  467. viz: 'echarts_timeseries_line',
  468. });
  469. // label Anthony
  470. cy.get(
  471. '[data-test-chart-name="Top 10 California Names Timeseries"] .line .nv-legend-symbol',
  472. )
  473. .first()
  474. .should('have.css', 'fill', 'rgb(31, 168, 201)');
  475. // open 2nd main tab
  476. openTab(0, 1);
  477. waitForChartLoad({ name: 'Trends', viz: 'echarts_timeseries_line' });
  478. // label Andrew
  479. cy.get('[data-test-chart-name="Trends"] .line .nv-legend-symbol')
  480. .eq(1)
  481. .should('have.css', 'fill', 'rgb(69, 78, 124)');
  482. });
  483. it.skip('should not change colors on refreshes with color scheme set', () => {
  484. visitEdit(TABBED_DASHBOARD);
  485. openProperties();
  486. selectColorScheme('blueToGreen');
  487. applyChanges();
  488. saveChanges();
  489. // open nested tab
  490. openTab(1, 1);
  491. waitForChartLoad({
  492. name: 'Top 10 California Names Timeseries',
  493. viz: 'echarts_timeseries_line',
  494. });
  495. // label Anthony
  496. cy.get(
  497. '[data-test-chart-name="Top 10 California Names Timeseries"] .line .nv-legend-symbol',
  498. )
  499. .first()
  500. .should('have.css', 'fill', 'rgb(50, 0, 167)');
  501. // open 2nd main tab
  502. openTab(0, 1);
  503. waitForChartLoad({ name: 'Trends', viz: 'echarts_timeseries_line' });
  504. // label Andrew
  505. cy.get('[data-test-chart-name="Trends"] .line .nv-legend-symbol')
  506. .eq(1)
  507. .should('have.css', 'fill', 'rgb(0, 76, 218)');
  508. visit(TABBED_DASHBOARD);
  509. // open nested tab
  510. openTab(1, 1);
  511. waitForChartLoad({
  512. name: 'Top 10 California Names Timeseries',
  513. viz: 'echarts_timeseries_line',
  514. });
  515. // label Anthony
  516. cy.get(
  517. '[data-test-chart-name="Top 10 California Names Timeseries"] .line .nv-legend-symbol',
  518. )
  519. .first()
  520. .should('have.css', 'fill', 'rgb(50, 0, 167)');
  521. // open 2nd main tab
  522. openTab(0, 1);
  523. waitForChartLoad({ name: 'Trends', viz: 'echarts_timeseries_line' });
  524. // label Andrew
  525. cy.get('[data-test-chart-name="Trends"] .line .nv-legend-symbol')
  526. .eq(1)
  527. .should('have.css', 'fill', 'rgb(0, 76, 218)');
  528. });
  529. it.skip('should respect chart color scheme when none is set for the dashboard', () => {
  530. visit(TABBED_DASHBOARD);
  531. // open nested tab
  532. openTab(1, 1);
  533. waitForChartLoad({
  534. name: 'Top 10 California Names Timeseries',
  535. viz: 'echarts_timeseries_line',
  536. });
  537. // label Anthony
  538. cy.get(
  539. '[data-test-chart-name="Top 10 California Names Timeseries"] .line .nv-legend-symbol',
  540. )
  541. .first()
  542. .should('have.css', 'fill', 'rgb(31, 168, 201)');
  543. });
  544. it.skip('should apply same color to same labels with color scheme set on refresh', () => {
  545. visitEdit(TABBED_DASHBOARD);
  546. openProperties();
  547. selectColorScheme('blueToGreen');
  548. applyChanges();
  549. saveChanges();
  550. // open nested tab
  551. openTab(1, 1);
  552. waitForChartLoad({
  553. name: 'Top 10 California Names Timeseries',
  554. viz: 'echarts_timeseries_line',
  555. });
  556. // label Anthony
  557. cy.get(
  558. '[data-test-chart-name="Top 10 California Names Timeseries"] .line .nv-legend-symbol',
  559. )
  560. .first()
  561. .should('have.css', 'fill', 'rgb(50, 0, 167)');
  562. // open 2nd main tab
  563. openTab(0, 1);
  564. waitForChartLoad({ name: 'Trends', viz: 'echarts_timeseries_line' });
  565. // label Anthony
  566. cy.get('[data-test-chart-name="Trends"] .line .nv-legend-symbol')
  567. .eq(2)
  568. .should('have.css', 'fill', 'rgb(50, 0, 167)');
  569. visit(TABBED_DASHBOARD);
  570. // open nested tab
  571. openTab(1, 1);
  572. waitForChartLoad({
  573. name: 'Top 10 California Names Timeseries',
  574. viz: 'echarts_timeseries_line',
  575. });
  576. // label Anthony
  577. cy.get(
  578. '[data-test-chart-name="Top 10 California Names Timeseries"] .line .nv-legend-symbol',
  579. )
  580. .first()
  581. .should('have.css', 'fill', 'rgb(50, 0, 167)');
  582. // open 2nd main tab
  583. openTab(0, 1);
  584. waitForChartLoad({ name: 'Trends', viz: 'echarts_timeseries_line' });
  585. // label Anthony
  586. cy.get('[data-test-chart-name="Trends"] .line .nv-legend-symbol')
  587. .eq(2)
  588. .should('have.css', 'fill', 'rgb(50, 0, 167)');
  589. });
  590. it.skip('should apply same color to same labels with no color scheme set on refresh', () => {
  591. visit(TABBED_DASHBOARD);
  592. // open nested tab
  593. openTab(1, 1);
  594. waitForChartLoad({
  595. name: 'Top 10 California Names Timeseries',
  596. viz: 'echarts_timeseries_line',
  597. });
  598. // label Anthony
  599. cy.get(
  600. '[data-test-chart-name="Top 10 California Names Timeseries"] .line .nv-legend-symbol',
  601. )
  602. .first()
  603. .should('have.css', 'fill', 'rgb(31, 168, 201)');
  604. // open 2nd main tab
  605. openTab(0, 1);
  606. waitForChartLoad({ name: 'Trends', viz: 'echarts_timeseries_line' });
  607. // label Anthony
  608. cy.get('[data-test-chart-name="Trends"] .line .nv-legend-symbol')
  609. .eq(2)
  610. .should('have.css', 'fill', 'rgb(31, 168, 201)');
  611. visit(TABBED_DASHBOARD);
  612. // open nested tab
  613. openTab(1, 1);
  614. waitForChartLoad({
  615. name: 'Top 10 California Names Timeseries',
  616. viz: 'echarts_timeseries_line',
  617. });
  618. // label Anthony
  619. cy.get(
  620. '[data-test-chart-name="Top 10 California Names Timeseries"] .line .nv-legend-symbol',
  621. )
  622. .first()
  623. .should('have.css', 'fill', 'rgb(31, 168, 201)');
  624. // open 2nd main tab
  625. openTab(0, 1);
  626. waitForChartLoad({ name: 'Trends', viz: 'echarts_timeseries_line' });
  627. // label Anthony
  628. cy.get('[data-test-chart-name="Trends"] .line .nv-legend-symbol')
  629. .eq(2)
  630. .should('have.css', 'fill', 'rgb(31, 168, 201)');
  631. });
  632. it.skip('custom label colors should take the precedence in nested tabs', () => {
  633. visitEdit(TABBED_DASHBOARD);
  634. openProperties();
  635. openAdvancedProperties();
  636. clearMetadata();
  637. writeMetadata(
  638. '{"color_scheme":"lyftColors","label_colors":{"Anthony":"red","Bangladesh":"red"}}',
  639. );
  640. applyChanges();
  641. saveChanges();
  642. // open nested tab
  643. openTab(1, 1);
  644. waitForChartLoad({
  645. name: 'Top 10 California Names Timeseries',
  646. viz: 'echarts_timeseries_line',
  647. });
  648. cy.get(
  649. '[data-test-chart-name="Top 10 California Names Timeseries"] .line .nv-legend-symbol',
  650. )
  651. .first()
  652. .should('have.css', 'fill', 'rgb(255, 0, 0)');
  653. // open another nested tab
  654. openTab(2, 1);
  655. waitForChartLoad({ name: 'Growth Rate', viz: 'echarts_timeseries_line' });
  656. cy.get('[data-test-chart-name="Growth Rate"] .line .nv-legend-symbol')
  657. .first()
  658. .should('have.css', 'fill', 'rgb(255, 0, 0)');
  659. });
  660. it.skip('label colors should take the precedence for rendered charts in nested tabs', () => {
  661. visitEdit(TABBED_DASHBOARD);
  662. // open the tab first time and let chart load
  663. openTab(1, 1);
  664. waitForChartLoad({
  665. name: 'Top 10 California Names Timeseries',
  666. viz: 'echarts_timeseries_line',
  667. });
  668. // go to previous tab
  669. openTab(1, 0);
  670. openProperties();
  671. openAdvancedProperties();
  672. clearMetadata();
  673. writeMetadata(
  674. '{"color_scheme":"lyftColors","label_colors":{"Anthony":"red"}}',
  675. );
  676. applyChanges();
  677. saveChanges();
  678. // re-open the tab
  679. openTab(1, 1);
  680. cy.get(
  681. '[data-test-chart-name="Top 10 California Names Timeseries"] .line .nv-legend-symbol',
  682. )
  683. .first()
  684. .should('have.css', 'fill', 'rgb(255, 0, 0)');
  685. });
  686. it.skip('should re-apply original color after removing custom label color with color scheme set', () => {
  687. visitEdit(TABBED_DASHBOARD);
  688. openProperties();
  689. openAdvancedProperties();
  690. clearMetadata();
  691. writeMetadata(
  692. '{"color_scheme":"lyftColors","label_colors":{"Anthony":"red"}}',
  693. );
  694. applyChanges();
  695. saveChanges();
  696. openTab(1, 1);
  697. cy.get(
  698. '[data-test-chart-name="Top 10 California Names Timeseries"] .line .nv-legend-symbol',
  699. )
  700. .first()
  701. .should('have.css', 'fill', 'rgb(255, 0, 0)');
  702. editDashboard();
  703. openProperties();
  704. openAdvancedProperties();
  705. clearMetadata();
  706. writeMetadata('{"color_scheme":"lyftColors","label_colors":{}}');
  707. applyChanges();
  708. saveChanges();
  709. cy.get(
  710. '[data-test-chart-name="Top 10 California Names Timeseries"] .line .nv-legend-symbol',
  711. )
  712. .first()
  713. .should('have.css', 'fill', 'rgb(234, 11, 140)');
  714. cy.get(
  715. '[data-test-chart-name="Top 10 California Names Timeseries"] .line .nv-legend-symbol',
  716. )
  717. .eq(1)
  718. .should('have.css', 'fill', 'rgb(108, 131, 142)');
  719. cy.get(
  720. '[data-test-chart-name="Top 10 California Names Timeseries"] .line .nv-legend-symbol',
  721. )
  722. .eq(2)
  723. .should('have.css', 'fill', 'rgb(41, 171, 226)');
  724. });
  725. it.skip('should re-apply original color after removing custom label color with no color scheme set', () => {
  726. visitEdit(TABBED_DASHBOARD);
  727. // open nested tab
  728. openTab(1, 1);
  729. waitForChartLoad({
  730. name: 'Top 10 California Names Timeseries',
  731. viz: 'echarts_timeseries_line',
  732. });
  733. cy.get(
  734. '[data-test-chart-name="Top 10 California Names Timeseries"] .line .nv-legend-symbol',
  735. )
  736. .first()
  737. .should('have.css', 'fill', 'rgb(31, 168, 201)');
  738. cy.get(
  739. '[data-test-chart-name="Top 10 California Names Timeseries"] .line .nv-legend-symbol',
  740. )
  741. .eq(1)
  742. .should('have.css', 'fill', 'rgb(69, 78, 124)');
  743. cy.get(
  744. '[data-test-chart-name="Top 10 California Names Timeseries"] .line .nv-legend-symbol',
  745. )
  746. .eq(2)
  747. .should('have.css', 'fill', 'rgb(90, 193, 137)');
  748. openProperties();
  749. // Expand Styling section first
  750. cy.contains('Styling').scrollIntoView();
  751. cy.contains('Styling').closest('.ant-collapse-header').click();
  752. cy.get('[aria-label="Select color scheme"]').should('have.value', '');
  753. openAdvancedProperties();
  754. clearMetadata();
  755. writeMetadata('{"color_scheme":"","label_colors":{"Anthony":"red"}}');
  756. applyChanges();
  757. saveChanges();
  758. openTab(1, 1);
  759. cy.get(
  760. '[data-test-chart-name="Top 10 California Names Timeseries"] .line .nv-legend-symbol',
  761. )
  762. .first()
  763. .should('have.css', 'fill', 'rgb(255, 0, 0)');
  764. editDashboard();
  765. openProperties();
  766. openAdvancedProperties();
  767. clearMetadata();
  768. writeMetadata('{"color_scheme":"","label_colors":{}}');
  769. applyChanges();
  770. saveChanges();
  771. cy.get(
  772. '[data-test-chart-name="Top 10 California Names Timeseries"] .line .nv-legend-symbol',
  773. )
  774. .first()
  775. .should('have.css', 'fill', 'rgb(31, 168, 201)');
  776. cy.get(
  777. '[data-test-chart-name="Top 10 California Names Timeseries"] .line .nv-legend-symbol',
  778. )
  779. .eq(1)
  780. .should('have.css', 'fill', 'rgb(69, 78, 124)');
  781. cy.get(
  782. '[data-test-chart-name="Top 10 California Names Timeseries"] .line .nv-legend-symbol',
  783. )
  784. .eq(2)
  785. .should('have.css', 'fill', 'rgb(90, 193, 137)');
  786. });
  787. it.skip('should show the same colors in Explore', () => {
  788. visitEdit(TABBED_DASHBOARD);
  789. openProperties();
  790. openAdvancedProperties();
  791. clearMetadata();
  792. writeMetadata(
  793. '{"color_scheme":"lyftColors","label_colors":{"Anthony":"red"}}',
  794. );
  795. applyChanges();
  796. saveChanges();
  797. // open nested tab
  798. openTab(1, 1);
  799. waitForChartLoad({
  800. name: 'Top 10 California Names Timeseries',
  801. viz: 'echarts_timeseries_line',
  802. });
  803. // label Anthony
  804. cy.get(
  805. '[data-test-chart-name="Top 10 California Names Timeseries"] .line .nv-legend-symbol',
  806. )
  807. .first()
  808. .should('have.css', 'fill', 'rgb(255, 0, 0)');
  809. openExploreWithDashboardContext('Top 10 California Names Timeseries');
  810. // label Anthony
  811. cy.get('[data-test="chart-container"] .line .nv-legend-symbol')
  812. .first()
  813. .should('have.css', 'fill', 'rgb(255, 0, 0)');
  814. });
  815. it.skip('should change color scheme multiple times', () => {
  816. visitEdit(TABBED_DASHBOARD);
  817. openProperties();
  818. selectColorScheme('blueToGreen');
  819. applyChanges();
  820. saveChanges();
  821. // open nested tab
  822. openTab(1, 1);
  823. waitForChartLoad({
  824. name: 'Top 10 California Names Timeseries',
  825. viz: 'echarts_timeseries_line',
  826. });
  827. // label Anthony
  828. cy.get(
  829. '[data-test-chart-name="Top 10 California Names Timeseries"] .line .nv-legend-symbol',
  830. )
  831. .first()
  832. .should('have.css', 'fill', 'rgb(50, 0, 167)');
  833. // open 2nd main tab
  834. openTab(0, 1);
  835. waitForChartLoad({ name: 'Trends', viz: 'echarts_timeseries_line' });
  836. // label Anthony
  837. cy.get('[data-test-chart-name="Trends"] .line .nv-legend-symbol')
  838. .eq(2)
  839. .should('have.css', 'fill', 'rgb(50, 0, 167)');
  840. editDashboard();
  841. openProperties();
  842. selectColorScheme('modernSunset');
  843. applyChanges();
  844. saveChanges();
  845. // label Anthony
  846. cy.get('[data-test-chart-name="Trends"] .line .nv-legend-symbol')
  847. .eq(2)
  848. .should('have.css', 'fill', 'rgb(0, 128, 246)');
  849. // open main tab and nested tab
  850. openTab(0, 0);
  851. openTab(1, 1);
  852. // label Anthony
  853. cy.get(
  854. '[data-test-chart-name="Top 10 California Names Timeseries"] .line .nv-legend-symbol',
  855. )
  856. .first()
  857. .should('have.css', 'fill', 'rgb(0, 128, 246)');
  858. });
  859. it.skip('should apply the color scheme across main tabs', () => {
  860. visitEdit(TABBED_DASHBOARD);
  861. openProperties();
  862. selectColorScheme('blueToGreen');
  863. applyChanges();
  864. saveChanges();
  865. // go to second tab
  866. openTab(0, 1);
  867. waitForChartLoad({ name: 'Trends', viz: 'echarts_timeseries_line' });
  868. cy.get('[data-test-chart-name="Trends"] .line .nv-legend-symbol')
  869. .first()
  870. .should('have.css', 'fill', 'rgb(50, 0, 167)');
  871. });
  872. it.skip('should apply the color scheme across main tabs for rendered charts', () => {
  873. visitEdit(TABBED_DASHBOARD);
  874. waitForChartLoad({ name: 'Treemap', viz: 'treemap_v2' });
  875. openProperties();
  876. selectColorScheme('blueToGreen');
  877. applyChanges();
  878. saveChanges();
  879. // go to second tab
  880. openTab(0, 1);
  881. waitForChartLoad({ name: 'Trends', viz: 'echarts_timeseries_line' });
  882. cy.get('[data-test-chart-name="Trends"] .line .nv-legend-symbol')
  883. .first()
  884. .should('have.css', 'fill', 'rgb(50, 0, 167)');
  885. // change scheme now that charts are rendered across the main tabs
  886. editDashboard();
  887. openProperties();
  888. selectColorScheme('modernSunset');
  889. applyChanges();
  890. saveChanges();
  891. cy.get('[data-test-chart-name="Trends"] .line .nv-legend-symbol')
  892. .first()
  893. .should('have.css', 'fill', 'rgb(0, 128, 246)');
  894. });
  895. it.skip('should apply the color scheme in nested tabs', () => {
  896. visitEdit(TABBED_DASHBOARD);
  897. openProperties();
  898. selectColorScheme('blueToGreen');
  899. applyChanges();
  900. saveChanges();
  901. // open nested tab
  902. openTab(1, 1);
  903. waitForChartLoad({
  904. name: 'Top 10 California Names Timeseries',
  905. viz: 'echarts_timeseries_line',
  906. });
  907. cy.get(
  908. '[data-test-chart-name="Top 10 California Names Timeseries"] .line .nv-legend-symbol',
  909. )
  910. .first()
  911. .should('have.css', 'fill', 'rgb(50, 0, 167)');
  912. // open another nested tab
  913. openTab(2, 1);
  914. waitForChartLoad({ name: 'Growth Rate', viz: 'echarts_timeseries_line' });
  915. cy.get('[data-test-chart-name="Growth Rate"] .line .nv-legend-symbol')
  916. .first()
  917. .should('have.css', 'fill', 'rgb(50, 0, 167)');
  918. });
  919. it.skip('should apply a valid color scheme for rendered charts in nested tabs', () => {
  920. visitEdit(TABBED_DASHBOARD);
  921. // open the tab first time and let chart load
  922. openTab(1, 1);
  923. waitForChartLoad({
  924. name: 'Top 10 California Names Timeseries',
  925. viz: 'echarts_timeseries_line',
  926. });
  927. // go to previous tab
  928. openTab(1, 0);
  929. openProperties();
  930. selectColorScheme('blueToGreen');
  931. applyChanges();
  932. saveChanges();
  933. // re-open the tab
  934. openTab(1, 1);
  935. cy.get(
  936. '[data-test-chart-name="Top 10 California Names Timeseries"] .line .nv-legend-symbol',
  937. )
  938. .first()
  939. .should('have.css', 'fill', 'rgb(50, 0, 167)');
  940. });
  941. });
  942. // NOTE: Edit properties modal functionality is now covered by comprehensive Jest tests
  943. // in src/dashboard/components/PropertiesModal/PropertiesModal.test.tsx
  944. // This removes flaky Cypress modal interaction tests in favor of reliable unit tests
  945. // NOTE: Edit mode functionality is now covered by Jest integration tests
  946. // These tests were consistently failing due to modal overlay issues in Cypress
  947. // The core functionality is better tested with reliable unit/integration tests
  948. // NOTE: Chart drag/drop functionality requires true E2E testing
  949. // Keeping minimal Cypress tests for drag/drop workflows only
  950. describe('Components', () => {
  951. beforeEach(() => {
  952. visitEdit();
  953. });
  954. it('should add charts', () => {
  955. // Force close any modal that might be open
  956. cy.get('body').then($body => {
  957. if ($body.find('.ant-modal-wrap').length > 0) {
  958. cy.get('body').type('{esc}', { force: true });
  959. cy.wait(1000);
  960. // If ESC doesn't work, try clicking the close button
  961. cy.get('.ant-modal-close').click({ force: true });
  962. cy.wait(500);
  963. }
  964. });
  965. cy.get('input[type="checkbox"]').scrollIntoView();
  966. cy.get('input[type="checkbox"]').click({ force: true });
  967. dragComponent();
  968. cy.getBySel('dashboard-component-chart-holder').should('have.length', 1);
  969. });
  970. it.skip('should remove added charts', () => {
  971. cy.get('input[type="checkbox"]').scrollIntoView();
  972. cy.get('input[type="checkbox"]').click({ force: true });
  973. dragComponent('Unicode Cloud');
  974. cy.getBySel('dashboard-component-chart-holder').should('have.length', 1);
  975. cy.getBySel('dashboard-delete-component-button').click();
  976. cy.getBySel('dashboard-component-chart-holder').should('have.length', 0);
  977. });
  978. it.skip('should add markdown component to dashboard', () => {
  979. cy.getBySel('dashboard-builder-component-pane-tabs-navigation')
  980. .find('#tabs-tab-2')
  981. .click();
  982. // add new markdown component
  983. dragComponent('Text', 'new-component', false);
  984. cy.getBySel('dashboard-markdown-editor')
  985. .should(
  986. 'have.text',
  987. '✨Header 1\n✨Header 2\n✨Header 3\n\nClick here to learn more about markdown formatting',
  988. )
  989. .click(10, 10);
  990. cy.getBySel('dashboard-component-chart-holder').contains(
  991. 'Click here to learn more about [markdown formatting](https://bit.ly/1dQOfRK)',
  992. );
  993. cy.getBySel('dashboard-markdown-editor').click();
  994. cy.getBySel('dashboard-markdown-editor').type('Test resize');
  995. resize(
  996. '[data-test="dashboard-markdown-editor"] .resizable-container div.resizable-container-handle--bottom + div',
  997. ).to(500, 600);
  998. cy.getBySel('dashboard-markdown-editor').contains('Test resize');
  999. });
  1000. });
  1001. // NOTE: Save functionality is now covered by Jest integration tests
  1002. // This eliminates flaky modal overlay issues while ensuring save workflow is tested
  1003. });