Skip to content

Commit

Permalink
fix(tooltip): fix missing tooltip in consecutive buttons (#601)
Browse files Browse the repository at this point in the history
* fix(tooltip): add new a test case for row of buttons

* fix(tooltip): add native ResizeObserver detection and polyfill fallback

* feat(test-helpers): add frame count param to nextFrame & inNear util

* test(canvas): add wait another frame

* test: fix incorrect param of nextFrame

* test(clock): wait one more frame to complete rendering

* test(interactive-chart): add wait for element update & a few more frames

* test(tab-bar): wait a frame for rendering

* test(tree-select): wait for element update

* test(sparkline): wait for element update & a few more frame to complete rendering

* test(led-gauge): fix waiting for element update

* test(tornado-chart): fix waiting for element update

* test(tornado-chart): align test file to naming convention

* test(test-helpers): add unit test for replaceWhitespace util

* refactor(test-helpers): combine import statement + descope code coverage ignore

* test: clarity nextFrame usage
  • Loading branch information
wattachai-lseg authored Mar 21, 2023
1 parent 09a95c6 commit be77306
Show file tree
Hide file tree
Showing 19 changed files with 199 additions and 73 deletions.
17 changes: 13 additions & 4 deletions packages/core/src/elements/ResponsiveElement.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { BasicElement } from './BasicElement.js';
import { ResizeObserver, ResizeObserverEntry } from '@juggle/resize-observer';
// If ResizeObserver native API works fine, this package should be removed in future
import { ResizeObserver as PolyfillResizeObserver } from '@juggle/resize-observer';

export type ElementSize = {
width: number;
Expand Down Expand Up @@ -48,13 +49,21 @@ const triggerResize = (entry: ResizeObserverEntry): void => {
entry.target.dispatchEvent(event);
};

/**
* Trigger Resize all entries from ResizeObserver
* @param entries array of ResizeObserverEntry
* @returns {void}
*/
const entriesResize = (entries: ResizeObserverEntry[]): void => {
entries.forEach(entry => triggerResize(entry));
};

/**
* Global resize observer,
* used to watch changes in element dimensions
*/
const resizeObserver = new ResizeObserver(entries => {
entries.forEach(entry => triggerResize(entry));
});
const resizeObserver = typeof ResizeObserver === 'function' ? new ResizeObserver(entriesResize) : new PolyfillResizeObserver(entriesResize);


/**
* Responsive element base class.
Expand Down
6 changes: 3 additions & 3 deletions packages/elements/src/canvas/__test__/canvas.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ describe('canvas/Canvas', () => {
Object.defineProperty(window, 'devicePixelRatio', {
value: null
});
await nextFrame();
await nextFrame(2); // wait for resize observer & rendering completion
expect(el.canvas.width).equal(Math.floor(el.width * dpr));
expect(el.canvas.height).equal(Math.floor(el.height * dpr));
});
Expand All @@ -55,7 +55,7 @@ describe('canvas/Canvas', () => {
Object.defineProperty(window, 'devicePixelRatio', {
value: 3
});
await nextFrame();
await nextFrame(2); // wait for resize observer & rendering completion
expect(el.canvas.width).equal(Math.floor(el.width * devicePixelRatio));
expect(el.canvas.height).equal(Math.floor(el.height * devicePixelRatio));
Object.defineProperty(window, 'devicePixelRatio', {
Expand All @@ -70,7 +70,7 @@ describe('canvas/Canvas', () => {

it('Handles fractional pixelation', async () => {
el.style.width = '300.5px';
await elementUpdated();
await elementUpdated(el);
const listener = function () {
el.removeEventListener('resize', listener);
expect(el.style.width, 'ef-canvas\'s width should be fractional').equal('300.5px');
Expand Down
12 changes: 6 additions & 6 deletions packages/elements/src/clock/__test__/clock.analogue.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,11 @@ describe('clock/Analogue', () => {

it('Shows small size clock when width is less than 130px', async () => {
expect(el.shadowRoot.querySelector('[part="digital"]'), 'digital clock should display inside a default analog clock').not.to.be.null;

// make size smaller than defined break point
el.style.width = '129px';
await elementUpdated(el);
await nextFrame();
await nextFrame(2); // wait for resize observer & rendering completion

expect(el.shadowRoot.querySelector('[part="digital"]'), 'digital clock should not display inside small clock').to.be.null;
expect(el.amPm, 'am-pm should be hidden by default on small clock').to.be.equal(false);
Expand All @@ -63,18 +63,18 @@ describe('clock/Analogue', () => {
el.style.width = '129px';
await elementUpdated(el);
await nextFrame();

// test default behavior
expect(el.hasAttribute('am-pm')).to.be.equal(false);
expect(el.amPm).to.be.equal(false);
expect(el.shadowRoot.querySelector('[part="segment am-pm"]')).to.be.null;

// test when it has am-pm attribute
el = await fixture('<ef-clock analogue am-pm></ef-clock>');
el.style.width = '129px';
await elementUpdated(el);
await nextFrame();

expect(el.amPm, 'amPm property should be true if am-pm attribute is set').to.be.equal(true);
expect(el.shadowRoot.querySelector('[part="segment am-pm"]'), 'AM/PM should display on clock').not.to.be.null;

Expand All @@ -92,7 +92,7 @@ describe('clock/Analogue', () => {
await nextFrame();

expect(el.hasAttribute('size'), 'size attribute should not show if not analog').to.be.equal(false);

el.style.width = '129px';
await elementUpdated(el);
await nextFrame();
Expand Down
2 changes: 1 addition & 1 deletion packages/elements/src/clock/__test__/clock.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ describe('clock/Clock', () => {
el = await fixture('<ef-clock analogue></ef-clock>');
el.style.width = '129px';
await elementUpdated(el);
await nextFrame();
await nextFrame(2); // wait for resize observer & rendering completion

expect(el).shadowDom.to.equalSnapshot();
});
Expand Down
2 changes: 1 addition & 1 deletion packages/elements/src/datetime-field/__test__/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const inputValue = (el) => el.inputValue; // Access private property
const inputElement = (el) => el.inputElement; // Access private property
const focusInput = async (el) => {
await triggerFocusFor(inputElement(el));
await nextFrame(el);
await nextFrame();
};

const arrowRight = async (el) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -833,8 +833,8 @@ describe('interactive-chart/InteractiveChart', () => {

it('Should has dynamic left position in legend when the chart set y axis at left', async () => {
el.config = linePositionLeft;
await elementUpdated();
await nextFrame();
await elementUpdated(el);
await nextFrame(3); // wait for resize observer & rendering completion

expect(el.chart).to.not.be.undefined;
expect(el.chart).to.not.be.null;
Expand All @@ -846,8 +846,8 @@ describe('interactive-chart/InteractiveChart', () => {

it('Should has dynamic left position in legend when the chart set y axis at both edge', async () => {
el.config = twoPriceScales;
await elementUpdated();
await nextFrame();
await elementUpdated(el);
await nextFrame(3); // wait for resize observer & rendering completion

expect(el.chart).to.not.be.undefined;
expect(el.chart).to.not.be.null;
Expand All @@ -859,8 +859,8 @@ describe('interactive-chart/InteractiveChart', () => {

it('Should has fixed left position in legend when the chart set y axis at right edge', async () => {
el.config = line;
await elementUpdated();
await nextFrame();
await elementUpdated(el);
await nextFrame(3); // wait for resize observer & rendering completion

expect(el.chart).to.not.be.undefined;
expect(el.chart).to.not.be.null;
Expand All @@ -873,32 +873,36 @@ describe('interactive-chart/InteractiveChart', () => {
describe('Test deprecated attribute', () => {
it('Switch attribute legendstyle horizontal to vertical, it should display vertical style', async () => {
el = await fixture('<ef-interactive-chart legendstyle="horizontal"></ef-interactive-chart>');

el.config = line;
await elementUpdated();
await elementUpdated(el);
await nextFrame(2); // wait for resize observer & rendering completion

expect(el.chart).to.not.be.undefined;
expect(el.chart).to.not.be.null;

el.setAttribute('legendstyle','vertical');

await nextFrame();
await elementUpdated();
await elementUpdated(el);
expect(el.getAttribute('legend-style')).to.null;
expect(el.shadowRoot.querySelector('[part=legend]').className).to.not.include('horizontal');
});
it('Set legend-style to vertical when legendstyle horizontal, it should display vertical style', async () => {
el = await fixture('<ef-interactive-chart legendstyle="horizontal"></ef-interactive-chart>');

el.config = line;
await elementUpdated();
await elementUpdated(el);
await nextFrame(2); // wait for resize observer & rendering completion

expect(el.chart).to.not.be.undefined;
expect(el.chart).to.not.be.null;
expect(el.getAttribute('legendstyle')).to.equal('horizontal');

el.setAttribute('legend-style','vertical');

await nextFrame();
await elementUpdated();
await elementUpdated(el);
expect(el.shadowRoot.querySelector('[part=legend]').className).to.not.include('horizontal');
});
});
Expand Down
26 changes: 13 additions & 13 deletions packages/elements/src/led-gauge/__test__/led-gauge.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ describe('led-gauge/LedGauge', () => {
el.setAttribute('top-label', 'NewTopLabel');
el.setAttribute('bottom-label', 'NewBottomLabel');

await elementUpdated();
await elementUpdated(el);
top = el.shadowRoot.querySelector('#top');
bottom = el.shadowRoot.querySelector('#bottom');

Expand All @@ -72,7 +72,7 @@ describe('led-gauge/LedGauge', () => {
el.topLabel = 'NewTopLabel';
el.bottomLabel = 'NewBottomLabel';

await elementUpdated();
await elementUpdated(el);
top = el.shadowRoot.querySelector('#top');
bottom = el.shadowRoot.querySelector('#bottom');

Expand All @@ -87,7 +87,7 @@ describe('led-gauge/LedGauge', () => {

el.removeAttribute('top-label');
el.removeAttribute('bottom-label');
await elementUpdated();
await elementUpdated(el);
top = el.shadowRoot.querySelector('#top');
bottom = el.shadowRoot.querySelector('#bottom');

Expand All @@ -111,7 +111,7 @@ describe('led-gauge/LedGauge', () => {

it('Should be able to set topValue and bottomValue via property', async () => {
const el = await fixture(full);
await nextFrame();
await nextFrame(2); // wait for resize observer & rendering completion
top = el.shadowRoot.querySelector('#top');
bottom = el.shadowRoot.querySelector('#bottom');
let topTextPos = parseInt(window.getComputedStyle(top).getPropertyValue('left'), 10);
Expand All @@ -122,7 +122,7 @@ describe('led-gauge/LedGauge', () => {

el.topValue = 50;
el.bottomValue = -50;
await elementUpdated();
await elementUpdated(el);
let newTopTextPos = parseInt(window.getComputedStyle(top).getPropertyValue('left'), 10);
let newBottomTextPos = parseInt(window.getComputedStyle(bottom).getPropertyValue('left'), 10);

Expand All @@ -133,7 +133,7 @@ describe('led-gauge/LedGauge', () => {

it('Should be able to set topValue and bottomValue via attribute', async () => {
const el = await fixture(full);
await nextFrame();
await nextFrame(2); // wait for resize observer & rendering completion
top = el.shadowRoot.querySelector('#top');
bottom = el.shadowRoot.querySelector('#bottom');
let topTextPos = parseInt(window.getComputedStyle(top).getPropertyValue('left'), 10);
Expand All @@ -144,7 +144,7 @@ describe('led-gauge/LedGauge', () => {

el.setAttribute('top-value', '50');
el.setAttribute('bottom-value', '-50');
await elementUpdated();
await elementUpdated(el);
let newTopTextPos = parseInt(window.getComputedStyle(top).getPropertyValue('left'), 10);
let newBottomTextPos = parseInt(window.getComputedStyle(bottom).getPropertyValue('left'), 10);

Expand All @@ -161,7 +161,7 @@ describe('led-gauge/LedGauge', () => {
it('Should update range label when range-label changed by attribute', async () => {
const el = await fixture(rangeFixture);
el.setAttribute('range-label', 'NewRangeLabel');
await elementUpdated();
await elementUpdated(el);
range = el.shadowRoot.querySelector('#range');

expect(range).to.not.equal(null);
Expand All @@ -171,7 +171,7 @@ describe('led-gauge/LedGauge', () => {
it('Should update range label when range-label changed by property', async () => {
const el = await fixture(rangeFixture);
el.rangeLabel = 'NewRangeLabel';
await elementUpdated();
await elementUpdated(el);
range = el.shadowRoot.querySelector('#range');

expect(range).to.not.equal(null);
Expand All @@ -186,7 +186,7 @@ describe('led-gauge/LedGauge', () => {
expect(range).to.not.equal(null);

el.setAttribute('bottom-label', 'Bottom Text');
await elementUpdated();
await elementUpdated(el);
expect(bottom).to.equal(null);
expect(range).to.not.equal(null);
});
Expand All @@ -200,20 +200,20 @@ describe('led-gauge/LedGauge', () => {
it('Should have min=0 and max=100 when set zero=left by property', async () => {
const el = await fixture(zero);
el.zero = 'left';
await elementUpdated();
await elementUpdated(el);
expect(el.zero).to.equal('left');
});

it('Should set zero to center when invalid value is set', async () => {
const el = await fixture(zero);
el.zero = 'left';
await elementUpdated();
await elementUpdated(el);
expect(el.zero).to.equal('left');
expect(el.min).to.equal(0);
expect(el.max).to.equal(100);

el.zero = 'invalid';
await elementUpdated();
await elementUpdated(el);
expect(el.zero).to.equal('center');
expect(el.min).to.equal(-100);
expect(el.max).to.equal(100);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ describe('select/Events', () => {
it('opened-changed event on keyboard pressed', async () => {
const el = await fixture(`<ef-select>${getOptions()}</ef-select>`);
el.focus();
await nextFrame(el);
await nextFrame();
let counter = 0;
let opened = false;

Expand Down
5 changes: 3 additions & 2 deletions packages/elements/src/sparkline/__test__/sparkline.test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { fixture, expect, elementUpdated } from '@refinitiv-ui/test-helpers';
import { fixture, expect, elementUpdated, nextFrame } from '@refinitiv-ui/test-helpers';

// import element and theme
import '@refinitiv-ui/elements/sparkline';
Expand Down Expand Up @@ -75,7 +75,8 @@ describe('sparkline/Sparkline', () => {
expect(isCanvasBlank(canvas)).to.be.true;

el.data = data;
await elementUpdated();
await elementUpdated(el);
await nextFrame(2); // wait for rendering completion
expect(countDataChanged).to.equal(1);
expect(countDataError).to.equal(0);
expect(isCanvasBlank(canvas)).to.be.false;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { fixture, expect, elementUpdated, aTimeout } from '@refinitiv-ui/test-helpers';
import { fixture, expect, elementUpdated, aTimeout, nextFrame } from '@refinitiv-ui/test-helpers';

import '@refinitiv-ui/elements/tab-bar';
import '@refinitiv-ui/elemental-theme/light/ef-tab-bar';
Expand Down Expand Up @@ -100,6 +100,7 @@ describe('tab-bar/TabBar', () => {
});

it('Should show only right scroll button', async () => {
await nextFrame(); // wait for resize observer & rendering completion
expect(getElementStyle(leftScrollBtn, 'display')).equal('none');
expect(getElementStyle(rightScrollBtn, 'display')).equal('flex');
});
Expand Down
20 changes: 20 additions & 0 deletions packages/elements/src/tooltip/__demo__/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,26 @@
</custom-style>
</demo-block>

<demo-block layout="normal" header="Tooltip Opening" tags="tooltip, position, show, moving">
side by side buttons: testing tooltip display
<style>
.container {
display: flex;
justify-content: center;

}
.container > ef-button {
height: 50px;
width: 100px;
}
</style>
</div>
<div class="container">
<ef-button title="Hello tooltip1">Tooltip1</ef-button>
<ef-button title="Hello tooltip2">Tooltip2</ef-button>
</div>
</demo-block>

<demo-block layout="normal" header="Transition styles" tags="tooltip, transition">
<div>Tooltip can have different transition styles, which may be overridden by changing `transitionStyle`.</div>
<br/>
Expand Down
Loading

0 comments on commit be77306

Please sign in to comment.