Skip to content

Commit

Permalink
Update/fix tests & performance debugging
Browse files Browse the repository at this point in the history
+ revert debugging in source code
  • Loading branch information
cee-chen committed Sep 22, 2023
1 parent 810583d commit 1d1506e
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 250 deletions.
4 changes: 2 additions & 2 deletions src/components/text_truncate/text_truncate.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ describe('EuiTextTruncate', () => {
{...props}
id="text1"
truncation="startEnd"
width={30}
width={20}
/>
<EuiTextTruncate
{...props}
Expand Down Expand Up @@ -336,7 +336,7 @@ describe('EuiTextTruncate', () => {
getTruncatedText().should('have.text', 'Lorem ipsum dolor sit amet, …');

cy.viewport(100, 50);
getTruncatedText().should('have.text', 'Lorem ipsum …');
getTruncatedText().should('have.text', 'Lorem ipsum…');
});
});
});
33 changes: 3 additions & 30 deletions src/components/text_truncate/text_truncate.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,9 @@ import { requiredProps } from '../../test';

// Util mocks
const mockEarlyReturn = { checkIfTruncationIsNeeded: () => false };
const mockCleanup = jest.fn();
jest.mock('./utils', () => {
return {
TruncationUtilsWithDOM: jest.fn(() => ({
...mockEarlyReturn,
cleanup: mockCleanup,
})),
TruncationUtilsWithCanvas: jest.fn(() => mockEarlyReturn),
};
});
import { TruncationUtilsWithCanvas } from './utils';
jest.mock('./utils', () => ({
TruncationUtils: jest.fn(() => mockEarlyReturn),
}));

import { EuiTextTruncate } from './text_truncate';

Expand Down Expand Up @@ -61,24 +53,5 @@ describe('EuiTextTruncate', () => {
});
});

describe('render API', () => {
it('calls the DOM cleanup method after each render', () => {
render(<EuiTextTruncate {...props} measurementRenderAPI="dom" />);
expect(mockCleanup).toHaveBeenCalledTimes(1);
});

it('allows switching to canvas rendering via `measurementRenderAPI`', () => {
render(
<EuiTextTruncate
width={100}
text="Canvas test"
measurementRenderAPI="canvas"
/>
);
expect(TruncationUtilsWithCanvas).toHaveBeenCalledTimes(1);
expect(mockCleanup).not.toHaveBeenCalled();
});
});

// We can't unit test the actual truncation logic in JSDOM - see Cypress spec tests instead
});
1 change: 0 additions & 1 deletion src/components/text_truncate/text_truncate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,6 @@ const EuiTextTruncateWithWidth: FunctionComponent<
container: containerEl,
availableWidth: width,
});
utils.debugPerformance = true;

if (utils.checkIfTruncationIsNeeded() === false) {
truncatedText = text;
Expand Down
138 changes: 23 additions & 115 deletions src/components/text_truncate/utils.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,7 @@
/// <reference types="cypress-real-events" />
/// <reference types="../../../cypress/support" />

import React, {
ReactNode,
FunctionComponent,
useState,
useEffect,
} from 'react';

import { TruncationUtilsWithDOM, TruncationUtilsWithCanvas } from './utils';
import { TruncationUtils } from './utils';

// CI doesn't have access to the Inter font, so we need to manually include it
// for font calculations to work correctly
Expand All @@ -34,23 +27,24 @@ before(() => {
});

describe('Truncation utils', () => {
const sharedProps = {
const params = {
fullText: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit',
availableWidth: 200,
ellipsis: '...',
};

// Note: These tests are intended to be primarily unit tests and do not emit
// any rendered output in the UI. The reason why they're tested in Cypress and
// not Jest is because jsdom does not return meaningful/valid width calculations
const expectedOutput = {
start: '...t, consectetur adipiscing elit',
end: 'Lorem ipsum dolor sit amet, ...',
startEnd: '...lor sit amet, consectetur a...',
middle: 'Lorem ipsum d...adipiscing elit',
};

// Note: the truncation type tests are intended to be primarily unit tests and do not
// emit any rendered output in the UI. The reason why they're tested in Cypress and
// not Jest is because jsdom does not return meaningful/valid width calculations
describe('shared truncation types logic', () => {
const utils = new TruncationUtilsWithCanvas({ ...sharedProps, font });
describe('truncation types logic', () => {
const utils = new TruncationUtils({ ...params, font });

describe('start', () => {
it('inserts ellipsis at the start of the text', () => {
Expand Down Expand Up @@ -140,7 +134,7 @@ describe('Truncation utils', () => {
after(() => document.body.removeChild(container));

describe('basic iterations', () => {
const utils = new TruncationUtilsWithDOM({ ...sharedProps, container });
const utils = new TruncationUtils({ ...params, container });

beforeEach(() => {
utils.debugPerformance = true;
Expand All @@ -152,23 +146,23 @@ describe('Truncation utils', () => {
expect(utils.debugCounter).to.equal(3);

utils.truncateStart(3);
expect(utils.debugCounter).to.equal(9);
expect(utils.debugCounter).to.equal(8);
});

specify('end', () => {
utils.truncateEnd();
expect(utils.debugCounter).to.equal(5);
expect(utils.debugCounter).to.equal(7);

utils.truncateEnd(3);
expect(utils.debugCounter).to.equal(12);
expect(utils.debugCounter).to.equal(14);
});

specify('startEnd', () => {
utils.truncateStartEndAtMiddle();
expect(utils.debugCounter).to.equal(5);
expect(utils.debugCounter).to.equal(4);

utils.truncateStartEndAtPosition(25);
expect(utils.debugCounter).to.equal(10);
expect(utils.debugCounter).to.equal(9);
});

specify('middle', () => {
Expand All @@ -178,10 +172,10 @@ describe('Truncation utils', () => {
});

it('maintains the same low number of iterations regardless of full text length', () => {
const utils = new TruncationUtilsWithDOM({
...sharedProps,
const utils = new TruncationUtils({
...params,
container,
fullText: sharedProps.fullText.repeat(100),
fullText: params.fullText.repeat(100),
});
utils.debugPerformance = true;

Expand All @@ -190,10 +184,10 @@ describe('Truncation utils', () => {
});

it('maintains the low numbers of iterations regardless of available width', () => {
const utils = new TruncationUtilsWithDOM({
...sharedProps,
const utils = new TruncationUtils({
...params,
container,
fullText: sharedProps.fullText.repeat(1000),
fullText: params.fullText.repeat(1000),
availableWidth: 1000,
});
utils.debugPerformance = true;
Expand All @@ -203,10 +197,10 @@ describe('Truncation utils', () => {
});

it('maintains low number of iterations in canvas as well as DOM', () => {
const utils = new TruncationUtilsWithCanvas({
...sharedProps,
const utils = new TruncationUtils({
...params,
font,
fullText: sharedProps.fullText.repeat(1000),
fullText: params.fullText.repeat(1000),
availableWidth: 1000,
});
utils.debugPerformance = true;
Expand All @@ -215,90 +209,4 @@ describe('Truncation utils', () => {
expect(utils.debugCounter).to.equal(6);
});
});

// Test utility for outputting the returned strings from each truncation utility
// in React. Given the same shared props and fonts, both render methods should
// arrive at the same truncated strings
const TestSetup: FunctionComponent<{
getUtils: () => TruncationUtilsWithDOM | TruncationUtilsWithCanvas;
}> = ({ getUtils }) => {
const [rendered, setRendered] = useState<ReactNode>(null);

useEffect(() => {
const utils = getUtils();
setRendered(
<div style={{ font }}>
<div id="start">{utils.truncateStart()}</div>
<div id="end">{utils.truncateEnd()}</div>
<div id="middle">{utils.truncateMiddle()}</div>
<div id="startEnd">{utils.truncateStartEndAtMiddle()}</div>
<div id="startEndAt">{utils.truncateStartEndAtPosition(15)}</div>
</div>
);
// @ts-ignore - the `?.` handles canvas which doesn't require a cleanup
utils.cleanup?.();
}, []); // eslint-disable-line react-hooks/exhaustive-deps

return <>{rendered}</>;
};

const assertExpectedOutput = () => {
cy.get('#start').should('have.text', expectedOutput.start);
cy.get('#end').should('have.text', expectedOutput.end);
cy.get('#middle').should('have.text', expectedOutput.middle);
cy.get('#startEnd').should('have.text', expectedOutput.startEnd);
cy.get('#startEndAt').should(
'have.text',
'...rem ipsum dolor sit amet, ...'
);
};

describe('TruncationUtilsWithDOM', () => {
const container = document.createElement('div');
container.style.font = font;
const props = { ...sharedProps, container };

it('truncates text as expected', () => {
cy.mount(
<TestSetup
getUtils={() => {
document.body.appendChild(container);
return new TruncationUtilsWithDOM(props);
}}
/>
);
assertExpectedOutput();
});
});

describe('TruncationUtilsWithCanvas', () => {
describe('container', () => {
const container = document.createElement('div');
container.style.font = font;
const props = { ...sharedProps, container };

it('truncates text as expected', () => {
cy.mount(
<TestSetup
getUtils={() => {
document.body.appendChild(container);
return new TruncationUtilsWithCanvas(props);
}}
/>
);
assertExpectedOutput();
});
});

describe('font', () => {
const props = { ...sharedProps, font };

it('truncates text as expected', () => {
cy.mount(
<TestSetup getUtils={() => new TruncationUtilsWithCanvas(props)} />
);
assertExpectedOutput();
});
});
});
});
Loading

0 comments on commit 1d1506e

Please sign in to comment.