Skip to content

Commit

Permalink
Track set/clear service/operation with tests
Browse files Browse the repository at this point in the history
Signed-off-by: Everett Ross <[email protected]>
  • Loading branch information
everett980 committed Nov 22, 2019
1 parent ff7b6e4 commit 8502c7e
Show file tree
Hide file tree
Showing 9 changed files with 164 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,19 @@ exports[`<DdgNodeContent> DdgNodeContent.getNodeRenderer() returns a <DdgNodeCon
<a
className="DdgNodeContent--actionsItem"
href="/deep-dependencies?operation=the-operation&service=the-service"
onClick={[Function]}
onClick={
[MockFunction] {
"calls": Array [
Array [],
],
"results": Array [
Object {
"isThrow": false,
"value": undefined,
},
],
}
}
>
<span
className="DdgNodeContent--actionsItemIconWrapper"
Expand Down Expand Up @@ -937,6 +949,7 @@ exports[`<DdgNodeContent> renders the number of operations if there are multiple
"op3",
]
}
setValue={[Function]}
value={null}
/>
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,12 @@ jest.mock('./calc-positioning', () => () => ({
/* eslint-disable import/first */
import React from 'react';
import { shallow } from 'enzyme';
import { Checkbox } from 'antd';
import { Checkbox, Popover } from 'antd';

import DdgNodeContent from '.';
import { MAX_LENGTH, MAX_LINKED_TRACES, MIN_LENGTH, PARAM_NAME_LENGTH, RADIUS } from './constants';
import * as track from '../../index.track';
import FilteredList from '../../../common/FilteredList';
import * as getSearchUrl from '../../../SearchTracePage/url';

import { ECheckedStatus, EDdgDensity, EDirection, EViewModifier } from '../../../../model/ddg/types';
Expand All @@ -34,6 +36,7 @@ describe('<DdgNodeContent>', () => {
const vertexKey = 'some-key';
const service = 'some-service';
const operation = 'some-operation';
const operationArray = ['op0', 'op1', 'op2', 'op3'];
const props = {
focalNodeUrl: 'some-url',
focusPathsThroughVertex: jest.fn(),
Expand All @@ -42,6 +45,7 @@ describe('<DdgNodeContent>', () => {
hideVertex: jest.fn(),
isFocalNode: false,
operation,
setOperation: jest.fn(),
setViewModifier: jest.fn(),
service,
updateGenerationVisibility: jest.fn(),
Expand All @@ -51,6 +55,7 @@ describe('<DdgNodeContent>', () => {
let wrapper;

beforeEach(() => {
props.getGenerationVisibility.mockReturnValue(null).mockClear();
props.getVisiblePathElems.mockReset();
props.setViewModifier.mockReset();
props.updateGenerationVisibility.mockReset();
Expand All @@ -69,7 +74,7 @@ describe('<DdgNodeContent>', () => {

it('renders the number of operations if there are multiple', () => {
expect(wrapper).toMatchSnapshot();
wrapper.setProps({ operation: ['op0', 'op1', 'op2', 'op3'] });
wrapper.setProps({ operation: operationArray });
expect(wrapper).toMatchSnapshot();
});

Expand Down Expand Up @@ -158,6 +163,17 @@ describe('<DdgNodeContent>', () => {
parentVisibility,
});
});

it('handles mouse over event after vis update would hide vertex before unmounting', () => {
props.getVisiblePathElems.mockReturnValue(undefined);
wrapper.simulate('mouseover', { type: 'mouseover' });

expect(wrapper.state()).toEqual({
childrenVisibility: null,
parentVisibility: null,
});
expect(props.setViewModifier).toHaveBeenCalledWith([], EViewModifier.Hovered, true);
});
});

describe('node interactions', () => {
Expand Down Expand Up @@ -193,6 +209,41 @@ describe('<DdgNodeContent>', () => {
});
});

describe('setFocus', () => {
let trackSetFocusSpy;

beforeAll(() => {
trackSetFocusSpy = jest.spyOn(track, 'trackSetFocus');
});

it('tracks when setFocus link is clicked', () => {
expect(trackSetFocusSpy).toHaveBeenCalledTimes(0);
wrapper.find(`[href="${props.focalNodeUrl}"]`).simulate('click');
expect(trackSetFocusSpy).toHaveBeenCalledTimes(1);
});
});

describe('setOperation', () => {
let trackSetOpSpy;

beforeAll(() => {
trackSetOpSpy = jest.spyOn(track, 'trackVertexSetOperation');
});

it('tracks when popover sets a value', () => {
wrapper.setProps({ operation: operationArray });
expect(trackSetOpSpy).not.toHaveBeenCalled();

const list = shallow(<div>{wrapper.find(Popover).prop('content')}</div>).find(FilteredList);
expect(list.prop('options')).toBe(operationArray);
expect(trackSetOpSpy).not.toHaveBeenCalled();

list.prop('setValue')(operationArray[operationArray.length - 1]);
expect(props.setOperation).toHaveBeenCalledWith(operationArray[operationArray.length - 1]);
expect(trackSetOpSpy).toHaveBeenCalledTimes(1);
});
});

describe('updateChildren', () => {
it('renders children visibility status indicator iff state.childrenVisibility is provided', () => {
const initialItemCount = wrapper.find('.DdgNodeContent--actionsItem').length;
Expand Down Expand Up @@ -320,17 +371,27 @@ describe('<DdgNodeContent>', () => {
return ids;
};
let getSearchUrlSpy;
const lastIDs = () => getSearchUrlSpy.mock.calls[getSearchUrlSpy.mock.calls.length - 1][0].traceID;
let trackViewTracesSpy;
const verifyLastIDs = expectedIDs => {
const getSearchUrlCallCount = getSearchUrlSpy.mock.calls.length;
const actualIDs = getSearchUrlSpy.mock.calls[getSearchUrlCallCount - 1][0].traceID;

expect(actualIDs.sort()).toEqual(expectedIDs.sort());
expect(trackViewTracesSpy).toHaveBeenCalledTimes(getSearchUrlCallCount);
};
let originalOpen;

beforeAll(() => {
originalOpen = window.open;
window.open = jest.fn();
getSearchUrlSpy = jest.spyOn(getSearchUrl, 'getUrl');
trackViewTracesSpy = jest.spyOn(track, 'trackViewTraces');
});

beforeEach(() => {
getSearchUrlSpy.mockClear();
window.open.mockReset();
trackViewTracesSpy.mockReset();
});

afterAll(() => {
Expand All @@ -347,7 +408,7 @@ describe('<DdgNodeContent>', () => {
const ids = makeIDsAndMock([1]);
click();

expect(lastIDs().sort()).toEqual([].concat(...ids).sort());
verifyLastIDs([].concat(...ids));
expect(props.getVisiblePathElems).toHaveBeenCalledTimes(1);
expect(props.getVisiblePathElems).toHaveBeenCalledWith(vertexKey);
});
Expand All @@ -356,22 +417,22 @@ describe('<DdgNodeContent>', () => {
const ids = makeIDsAndMock([3]);
click();

expect(lastIDs().sort()).toEqual([].concat(...ids).sort());
verifyLastIDs([].concat(...ids));
});

it('opens new tab viewing multiple traceIDs from multiple elems', () => {
const ids = makeIDsAndMock([3, 2]);
click();

expect(lastIDs().sort()).toEqual([].concat(...ids).sort());
verifyLastIDs([].concat(...ids));
});

it('ignores falsy and duplicate IDs', () => {
const ids = makeIDsAndMock([3, 3]);
falsifyDuplicateAndMock(ids);
click();

expect(lastIDs().sort()).toEqual([].concat(...ids).sort());
verifyLastIDs([].concat(...ids));
});

describe('MAX_LINKED_TRACES', () => {
Expand All @@ -386,14 +447,14 @@ describe('<DdgNodeContent>', () => {
mockReturn(ids);
click();

expect(lastIDs().sort()).toEqual(expected);
verifyLastIDs(expected);
});

it('does not count falsy and duplicate IDs towards MAX_LINKED_TRACES', () => {
falsifyDuplicateAndMock(ids);
click();

expect(lastIDs().sort()).toEqual(expected);
verifyLastIDs(expected);
});
});

Expand All @@ -413,14 +474,14 @@ describe('<DdgNodeContent>', () => {
mockReturn(ids);
click();

expect(lastIDs().sort()).toEqual(expected);
verifyLastIDs(expected);
});

it('does not count falsy and duplicate IDs towards MAX_LEN', () => {
falsifyDuplicateAndMock(ids);
click();

expect(lastIDs().sort()).toEqual(expected);
verifyLastIDs(expected);
});
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import {
WORD_RX,
} from './constants';
import { setFocusIcon } from './node-icons';
import { trackSetFocus, trackViewTraces } from '../../index.track';
import { trackSetFocus, trackViewTraces, trackVertexSetOperation } from '../../index.track';
import { getUrl } from '../../url';
import BreakableText from '../../../common/BreakableText';
import FilteredList from '../../../common/FilteredList';
Expand Down Expand Up @@ -146,6 +146,11 @@ export default class DdgNodeContent extends React.PureComponent<TProps, TState>
hideVertex(vertexKey);
};

private setOperation = (operation: string) => {
trackVertexSetOperation();
this.props.setOperation(operation);
};

private updateChildren = () => {
const { updateGenerationVisibility, vertexKey } = this.props;
updateGenerationVisibility(vertexKey, EDirection.Downstream);
Expand Down Expand Up @@ -209,7 +214,7 @@ export default class DdgNodeContent extends React.PureComponent<TProps, TState>

render() {
const { childrenVisibility, parentVisibility } = this.state;
const { focalNodeUrl, isFocalNode, isPositioned, operation, service, setOperation } = this.props;
const { focalNodeUrl, isFocalNode, isPositioned, operation, service } = this.props;

const { radius, svcWidth, opWidth, svcMarginTop } = calcPositioning(service, operation);
const scaleFactor = RADIUS / radius;
Expand Down Expand Up @@ -243,7 +248,7 @@ export default class DdgNodeContent extends React.PureComponent<TProps, TState>
cancel={() => {}}
options={operation}
value={null}
setValue={setOperation}
setValue={this.setOperation}
/>
}
placement="bottom"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ exports[`<Header> renders the hops selector if distanceToPathElems is provided 1
</header>
`;
exports[`<Header> renders the operation selector if a service is selected 1`] = `
exports[`<Header> renders the operation selector iff a service is selected 1`] = `
<header
className="DdgHeader"
>
Expand Down Expand Up @@ -124,7 +124,7 @@ exports[`<Header> renders the operation selector if a service is selected 1`] =
</header>
`;
exports[`<Header> renders the operation selector if a service is selected 2`] = `
exports[`<Header> renders the operation selector iff a service is selected 2`] = `
<header
className="DdgHeader"
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,26 @@ import MdVisibilityOff from 'react-icons/lib/md/visibility-off';
import Header from './index';
import HopsSelector from './HopsSelector';
import NameSelector from './NameSelector';
import * as track from '../index.track';

describe('<Header>', () => {
const minProps = {
clearOperation: () => {},
setDistance: () => {},
setOperation: () => {},
setOperation: jest.fn(),
setService: () => {},
};
const service = 'testService';
const services = [service];
const operation = 'testOperation';
const operations = [operation];
let trackSetOpSpy;
let wrapper;

beforeAll(() => {
trackSetOpSpy = jest.spyOn(track, 'trackHeaderSetOperation');
});

beforeEach(() => {
wrapper = shallow(<Header {...minProps} />);
});
Expand All @@ -49,8 +55,9 @@ describe('<Header>', () => {
expect(nameSelector.prop('label')).toMatch(/service/i);
});

it('renders the operation selector if a service is selected', () => {
it('renders the operation selector iff a service is selected', () => {
let nameSelector = wrapper.find(NameSelector);
expect(nameSelector.length).toBe(1);
wrapper.setProps({ service, services });
nameSelector = wrapper.find(NameSelector);
expect(nameSelector.length).toBe(2);
Expand All @@ -61,6 +68,19 @@ describe('<Header>', () => {
expect(wrapper).toMatchSnapshot();
});

it('tracks when operation selector sets a value', () => {
wrapper.setProps({ service, services });
const testOp = 'test operation';
expect(trackSetOpSpy).not.toHaveBeenCalled();

wrapper
.find(NameSelector)
.at(1)
.prop('setValue')(testOp);
expect(trackSetOpSpy).toHaveBeenCalledTimes(1);
expect(minProps.setOperation).toHaveBeenCalledWith(testOp);
});

it('renders the hops selector if distanceToPathElems is provided', () => {
wrapper.setProps({
distanceToPathElems: new Map(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import MdVisibilityOff from 'react-icons/lib/md/visibility-off';
import HopsSelector from './HopsSelector';
import NameSelector from './NameSelector';
import LayoutSettings from './LayoutSettings';
import { trackFilter, trackShowMatches } from '../index.track';
import { trackFilter, trackHeaderSetOperation, trackShowMatches } from '../index.track';
import UiFindInput from '../../common/UiFindInput';
import { EDirection, TDdgDistanceToPathElems, EDdgDensity } from '../../../model/ddg/types';

Expand Down Expand Up @@ -98,6 +98,11 @@ export default class Header extends React.PureComponent<TProps> {
);
};

setOperation = (operation: string) => {
trackHeaderSetOperation();
this.props.setOperation(operation);
};

handleInfoClick = () => {
trackShowMatches();
const { hiddenUiFindMatches, showVertices } = this.props;
Expand Down Expand Up @@ -141,7 +146,7 @@ export default class Header extends React.PureComponent<TProps> {
label="Operation"
placeholder="Filter by operation…"
value={operation || null}
setValue={setOperation}
setValue={this.setOperation}
options={operations || []}
/>
)}
Expand Down
Loading

0 comments on commit 8502c7e

Please sign in to comment.