diff --git a/src/model/crosshair.ts b/src/model/crosshair.ts index 798e20c94f..cfc366214c 100644 --- a/src/model/crosshair.ts +++ b/src/model/crosshair.ts @@ -255,6 +255,7 @@ export class Crosshair extends DataSource { this._pane = null; this.clearOriginCoord(); + this.updateAllViews(); } public paneViews(pane: Pane): readonly IPaneView[] { diff --git a/tests/e2e/graphics/helpers/screenshoter.ts b/tests/e2e/graphics/helpers/screenshoter.ts index 00cf423e1a..5b61317a09 100644 --- a/tests/e2e/graphics/helpers/screenshoter.ts +++ b/tests/e2e/graphics/helpers/screenshoter.ts @@ -9,6 +9,8 @@ import puppeteer, { Page, } from 'puppeteer'; +import { runInteractionsOnPage } from '../../helpers/perform-interactions'; + import { MouseEventParams } from '../../../../src/api/ichart-api'; import { TestCaseWindow } from './testcase-window-type'; @@ -108,6 +110,8 @@ export class Screenshoter { await waitForMouseMove; } + await runInteractionsOnPage(page); + // let's wait until the next af to make sure that everything is repainted await page.evaluate(() => { return new Promise((resolve: () => void) => { diff --git a/tests/e2e/graphics/test-cases/.eslintrc.cjs b/tests/e2e/graphics/test-cases/.eslintrc.cjs index ac1305f768..7c6eabf14a 100644 --- a/tests/e2e/graphics/test-cases/.eslintrc.cjs +++ b/tests/e2e/graphics/test-cases/.eslintrc.cjs @@ -6,7 +6,7 @@ module.exports = { node: false, }, rules: { - 'no-unused-vars': ['error', { varsIgnorePattern: '^runTestCase$', args: 'none' }], + 'no-unused-vars': ['error', { varsIgnorePattern: '^(runTestCase|beforeInteractions|after(Initial|Final)Interactions|(initial|final)InteractionsToPerform)$', args: 'none' }], }, globals: { LightweightCharts: false, diff --git a/tests/e2e/graphics/test-cases/dont-draw-crosshair-lines-when-mouse-leave.js b/tests/e2e/graphics/test-cases/dont-draw-crosshair-lines-when-mouse-leave.js new file mode 100644 index 0000000000..0466d24c7b --- /dev/null +++ b/tests/e2e/graphics/test-cases/dont-draw-crosshair-lines-when-mouse-leave.js @@ -0,0 +1,56 @@ +/* + When the mouse leaves the chart pane then the crosshair line should not be drawn +*/ + +window.ignoreMouseMove = true; + +function initialInteractionsToPerform() { + return [{ action: 'moveMouseCenter', target: 'container' }]; +} + +function finalInteractionsToPerform() { + return [{ action: 'moveMouseBottomRight', target: 'container' }]; +} + +function generateData() { + const res = []; + const time = new Date(Date.UTC(2023, 0, 1, 0, 0, 0, 0)); + + for (let i = 0; i < 12; ++i) { + res.push({ + time: time.getTime() / 1000, + value: i, + }); + + time.setUTCMonth(time.getUTCMonth() + 1); + } + + return res; +} + +function runTestCase(container) { + const chart = window.chart = LightweightCharts.createChart( + container, + { + layout: { attributionLogo: false }, + height: 450, + width: 450, + crosshair: { + vertLine: { + color: 'red', + width: 4, + style: 0, + }, + horzLine: { + color: 'red', + width: 4, + style: 0, + }, + }, + } + ); + + const series = chart.addSeries(LightweightCharts.LineSeries); + series.setData(generateData()); + chart.timeScale().fitContent(); +} diff --git a/tests/e2e/helpers/perform-interactions.ts b/tests/e2e/helpers/perform-interactions.ts index 0eb460051c..3431c67505 100644 --- a/tests/e2e/helpers/perform-interactions.ts +++ b/tests/e2e/helpers/perform-interactions.ts @@ -33,6 +33,7 @@ export type InteractionAction = | 'kineticAnimation' | 'moveMouseCenter' | 'moveMouseTopLeft' + | 'moveMouseBottomRight' | 'clickXY'; export type InteractionTarget = | 'container' @@ -189,6 +190,17 @@ async function performAction( } } break; + case 'moveMouseBottomRight': + { + const boundingBox = await target.boundingBox(); + if (boundingBox) { + await page.mouse.move( + boundingBox.x + boundingBox.width, + boundingBox.y + boundingBox.height + ); + } + } + break; default: { const exhaustiveCheck: never = action; throw new Error(exhaustiveCheck); @@ -248,3 +260,54 @@ export async function performInteractions( await performAction(interaction, page, target); } } + +interface InternalWindowForInteractions { + initialInteractionsToPerform: () => Interaction[]; + finalInteractionsToPerform: () => Interaction[]; + afterInitialInteractions?: () => void; + afterFinalInteractions?: () => void; +} + +export async function runInteractionsOnPage(page: Page): Promise { + const initialInteractionsToPerform = await page.evaluate(() => { + if (!(window as unknown as InternalWindowForInteractions).initialInteractionsToPerform) { + return []; + } + return (window as unknown as InternalWindowForInteractions).initialInteractionsToPerform(); + }); + + await performInteractions(page, initialInteractionsToPerform); + + await page.evaluate(() => { + if ((window as unknown as InternalWindowForInteractions).afterInitialInteractions) { + return ( + window as unknown as InternalWindowForInteractions + ).afterInitialInteractions?.(); + } + return new Promise((resolve: () => void) => { + window.requestAnimationFrame(() => { + setTimeout(resolve, 50); + }); + }); + }); + + const finalInteractionsToPerform = await page.evaluate(() => { + if (!(window as unknown as InternalWindowForInteractions).finalInteractionsToPerform) { + return []; + } + return (window as unknown as InternalWindowForInteractions).finalInteractionsToPerform(); + }); + + if (finalInteractionsToPerform && finalInteractionsToPerform.length > 0) { + await performInteractions(page, finalInteractionsToPerform); + } + + await page.evaluate(() => { + return new Promise((resolve: () => void) => { + (window as unknown as InternalWindowForInteractions).afterFinalInteractions?.(); + window.requestAnimationFrame(() => { + setTimeout(resolve, 50); + }); + }); + }); +} diff --git a/tests/e2e/interactions/interactions-test-cases.ts b/tests/e2e/interactions/interactions-test-cases.ts index 8bd6b99dff..371759e4dd 100644 --- a/tests/e2e/interactions/interactions-test-cases.ts +++ b/tests/e2e/interactions/interactions-test-cases.ts @@ -11,10 +11,7 @@ import puppeteer, { } from 'puppeteer'; import { TestCase } from '../helpers/get-test-cases'; -import { - Interaction, - performInteractions, -} from '../helpers/perform-interactions'; +import { Interaction, runInteractionsOnPage } from '../helpers/perform-interactions'; import { retryTest } from '../helpers/retry-tests'; import { getTestCases } from './helpers/get-interaction-test-cases'; @@ -101,47 +98,7 @@ void describe('Interactions tests', () => { return (window as unknown as InternalWindow).finishedSetup; }); - const initialInteractionsToPerform = await page.evaluate(() => { - if (!(window as unknown as InternalWindow).initialInteractionsToPerform) { - return []; - } - return (window as unknown as InternalWindow).initialInteractionsToPerform(); - }); - - await performInteractions(page, initialInteractionsToPerform); - - await page.evaluate(() => { - if ((window as unknown as InternalWindow).afterInitialInteractions) { - return ( - window as unknown as InternalWindow - ).afterInitialInteractions?.(); - } - return new Promise((resolve: () => void) => { - window.requestAnimationFrame(() => { - setTimeout(resolve, 50); - }); - }); - }); - - const finalInteractionsToPerform = await page.evaluate(() => { - if (!(window as unknown as InternalWindow).finalInteractionsToPerform) { - return []; - } - return (window as unknown as InternalWindow).finalInteractionsToPerform(); - }); - - if (finalInteractionsToPerform && finalInteractionsToPerform.length > 0) { - await performInteractions(page, finalInteractionsToPerform); - } - - await page.evaluate(() => { - return new Promise((resolve: () => void) => { - (window as unknown as InternalWindow).afterFinalInteractions(); - window.requestAnimationFrame(() => { - setTimeout(resolve, 50); - }); - }); - }); + await runInteractionsOnPage(page); await page.close();