immutable#is JavaScript Examples
The following examples show how to use
immutable#is.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: getHTML.js From spring-boot-ecommerce with Apache License 2.0 | 6 votes |
function getStyleRanges(text, charMetaList) {
var charStyle = EMPTY_SET;
var prevCharStyle = EMPTY_SET;
var ranges = [];
var rangeStart = 0;
for (var i = 0, len = text.length; i < len; i++) {
prevCharStyle = charStyle;
var meta = charMetaList.get(i);
charStyle = meta ? meta.getStyle() : EMPTY_SET;
if (i > 0 && !is(charStyle, prevCharStyle)) {
ranges.push([text.slice(rangeStart, i), prevCharStyle]);
rangeStart = i;
}
}
ranges.push([text.slice(rangeStart), charStyle]);
return ranges;
}
Example #2
Source File: root-test.js From ThreatMapper with Apache License 2.0 | 4 votes |
// Root reducer test suite using Jasmine matchers
describe('RootReducer', () => {
const ActionTypes = require('../../constants/action-types').default;
const reducer = require('../root').default;
const { initialState } = require('../root');
const topologyUtils = require('../../utils/topology-utils');
const topologySelectors = require('../../selectors/topology');
// TODO maybe extract those to topology-utils tests?
const { activeTopologyOptionsSelector } = topologySelectors;
const { getAdjacentNodes, isNodesDisplayEmpty, isTopologyNodeCountZero } = topologyUtils;
const { getUrlState } = require('../../utils/router-utils');
// fixtures
const NODE_SET = {
n1: {
adjacency: ['n1', 'n2'],
filtered: false,
id: 'n1',
},
n2: {
filtered: false,
id: 'n2',
}
};
const topologies = [
{
fullName: 'Processes',
hide_if_empty: true,
id: 'processes',
name: 'Processes',
options: [
{
defaultValue: 'hide',
id: 'unconnected',
options: [
{
label: 'Unconnected nodes hidden',
value: 'hide'
}
],
selectType: 'one'
}
],
rank: 1,
stats: {
edge_count: 379,
filtered_nodes: 214,
node_count: 320,
nonpseudo_node_count: 320
},
sub_topologies: [],
url: '/api/topology/processes'
},
{
hide_if_empty: true,
name: 'Pods',
options: [
{
defaultValue: 'default',
id: 'namespace',
options: [
{
label: 'monitoring',
value: 'monitoring'
},
{
label: 'scope',
value: 'scope'
},
{
label: 'All Namespaces',
value: 'all'
}
],
selectType: 'many'
},
{
defaultValue: 'hide',
id: 'pseudo',
options: [
{
label: 'Show Unmanaged',
value: 'show'
},
{
label: 'Hide Unmanaged',
value: 'hide'
}
]
}
],
rank: 3,
stats: {
edge_count: 15,
filtered_nodes: 16,
node_count: 32,
nonpseudo_node_count: 27
},
sub_topologies: [
{
hide_if_empty: true,
name: 'services',
options: [
{
defaultValue: 'default',
id: 'namespace',
options: [
{
label: 'monitoring',
value: 'monitoring'
},
{
label: 'scope',
value: 'scope'
},
{
label: 'All Namespaces',
value: 'all'
}
],
selectType: 'many'
}
],
rank: 0,
stats: {
edge_count: 14,
filtered_nodes: 16,
node_count: 159,
nonpseudo_node_count: 154
},
url: '/api/topology/services'
}
],
url: '/api/topology/pods'
}
];
// actions
const ChangeTopologyOptionAction = {
option: 'option1',
topologyId: 'topo1',
type: ActionTypes.CHANGE_TOPOLOGY_OPTION,
value: ['on']
};
const ChangeTopologyOptionAction2 = {
option: 'option1',
topologyId: 'topo1',
type: ActionTypes.CHANGE_TOPOLOGY_OPTION,
value: ['off']
};
const ClickNodeAction = {
nodeId: 'n1',
type: ActionTypes.CLICK_NODE
};
const ClickNode2Action = {
nodeId: 'n2',
type: ActionTypes.CLICK_NODE
};
const ClickRelativeAction = {
nodeId: 'rel1',
type: ActionTypes.CLICK_RELATIVE
};
const ClickShowTopologyForNodeAction = {
nodeId: 'rel1',
topologyId: 'topo2',
type: ActionTypes.CLICK_SHOW_TOPOLOGY_FOR_NODE
};
const ClickSubTopologyAction = {
topologyId: 'topo1-grouped',
type: ActionTypes.CLICK_TOPOLOGY
};
const ClickTopologyAction = {
topologyId: 'topo1',
type: ActionTypes.CLICK_TOPOLOGY
};
const ClickTopology2Action = {
topologyId: 'topo2',
type: ActionTypes.CLICK_TOPOLOGY
};
const CloseWebsocketAction = {
type: ActionTypes.CLOSE_WEBSOCKET
};
const deSelectNode = {
type: ActionTypes.DESELECT_NODE
};
const OpenWebsocketAction = {
type: ActionTypes.OPEN_WEBSOCKET
};
const ReceiveNodesDeltaAction = {
delta: {
add: [{
adjacency: ['n1', 'n2'],
id: 'n1'
}, {
id: 'n2'
}]
},
type: ActionTypes.RECEIVE_NODES_DELTA
};
const ReceiveNodesDeltaUpdateAction = {
delta: {
remove: ['n2'],
update: [{
adjacency: ['n1'],
id: 'n1'
}]
},
type: ActionTypes.RECEIVE_NODES_DELTA
};
const ReceiveTopologiesAction = {
topologies: [{
name: 'Topo1',
options: [{
defaultValue: 'off',
id: 'option1',
options: [
{value: 'on'},
{value: 'off'}
]
}],
stats: {
node_count: 1
},
sub_topologies: [{
name: 'topo 1 grouped',
url: '/topo1-grouped'
}],
url: '/topo1'
}, {
name: 'Topo2',
stats: {
node_count: 0
},
sub_topologies: [{
name: 'topo 2 sub',
url: '/topo2-sub'
}],
url: '/topo2'
}],
type: ActionTypes.RECEIVE_TOPOLOGIES
};
const ReceiveTopologiesHiddenAction = {
topologies: [{
name: 'Topo1',
stats: {
node_count: 1
},
url: '/topo1'
}, {
hide_if_empty: true,
name: 'Topo2',
stats: { filtered_nodes: 0, node_count: 0 },
sub_topologies: [{
hide_if_empty: true,
name: 'topo 2 sub',
stats: { filtered_nodes: 0, node_count: 0 },
url: '/topo2-sub',
}],
url: '/topo2'
}],
type: ActionTypes.RECEIVE_TOPOLOGIES
};
const RouteAction = {
state: {},
type: ActionTypes.ROUTE_TOPOLOGY
};
const ChangeInstanceAction = {
type: ActionTypes.CHANGE_INSTANCE
};
// Basic tests
it('returns initial state', () => {
const nextState = reducer(undefined, {});
expect(is(nextState, initialState)).toBeTruthy();
});
// topology tests
it('init with no topologies', () => {
const nextState = reducer(undefined, {});
expect(nextState.get('topologies').size).toBe(0);
expect(nextState.get('currentTopology')).toBeFalsy();
});
it('get current topology', () => {
let nextState = initialState;
nextState = reducer(nextState, ReceiveTopologiesAction);
nextState = reducer(nextState, ClickTopologyAction);
expect(nextState.get('topologies').size).toBe(2);
expect(nextState.get('currentTopology').get('name')).toBe('Topo1');
expect(nextState.get('currentTopology').get('url')).toBe('/topo1');
expect(nextState.get('currentTopology').get('options').first().get('id')).toEqual('option1');
expect(nextState.getIn(['currentTopology', 'options']).toJS()).toEqual([{
defaultValue: 'off',
id: 'option1',
options: [
{ value: 'on'},
{ value: 'off'}
],
selectType: 'one'
}]);
});
it('get sub-topology', () => {
let nextState = initialState;
nextState = reducer(nextState, ReceiveTopologiesAction);
nextState = reducer(nextState, ClickSubTopologyAction);
expect(nextState.get('topologies').size).toBe(2);
expect(nextState.get('currentTopology').get('name')).toBe('topo 1 grouped');
expect(nextState.get('currentTopology').get('url')).toBe('/topo1-grouped');
expect(nextState.get('currentTopology').get('options')).toBeUndefined();
});
// topology options
it('changes topology option', () => {
let nextState = initialState;
nextState = reducer(nextState, ReceiveTopologiesAction);
nextState = reducer(nextState, ClickTopologyAction);
// default options
expect(activeTopologyOptionsSelector(nextState).has('option1')).toBeTruthy();
expect(activeTopologyOptionsSelector(nextState).get('option1')).toBeInstanceOf(Array);
expect(activeTopologyOptionsSelector(nextState).get('option1')).toEqual(['off']);
expect(getUrlState(nextState).topologyOptions).toBeUndefined();
// turn on
nextState = reducer(nextState, ChangeTopologyOptionAction);
expect(activeTopologyOptionsSelector(nextState).get('option1')).toEqual(['on']);
expect(getUrlState(nextState).topologyOptions.topo1.option1).toEqual(['on']);
// turn off
nextState = reducer(nextState, ChangeTopologyOptionAction2);
expect(activeTopologyOptionsSelector(nextState).get('option1')).toEqual(['off']);
expect(getUrlState(nextState).topologyOptions).toBeUndefined();
// sub-topology should retain main topo options
nextState = reducer(nextState, ClickSubTopologyAction);
expect(activeTopologyOptionsSelector(nextState).get('option1')).toEqual(['off']);
expect(getUrlState(nextState).topologyOptions).toBeUndefined();
// other topology w/o options dont return options, but keep in app state
nextState = reducer(nextState, ClickTopology2Action);
expect(activeTopologyOptionsSelector(nextState).size).toEqual(0);
expect(getUrlState(nextState).topologyOptions).toBeUndefined();
});
it('adds/removes a topology option', () => {
const addAction = {
option: 'namespace',
topologyId: 'services',
type: ActionTypes.CHANGE_TOPOLOGY_OPTION,
value: ['default', 'scope'],
};
const removeAction = {
option: 'namespace',
topologyId: 'services',
type: ActionTypes.CHANGE_TOPOLOGY_OPTION,
value: ['default']
};
let nextState = initialState;
nextState = reducer(nextState, { topologies, type: ActionTypes.RECEIVE_TOPOLOGIES});
nextState = reducer(nextState, { topologyId: 'services', type: ActionTypes.CLICK_TOPOLOGY });
nextState = reducer(nextState, addAction);
expect(activeTopologyOptionsSelector(nextState).toJS()).toEqual({
namespace: ['default', 'scope'],
pseudo: ['hide']
});
nextState = reducer(nextState, removeAction);
expect(activeTopologyOptionsSelector(nextState).toJS()).toEqual({
namespace: ['default'],
pseudo: ['hide']
});
});
it('sets topology options from route', () => {
RouteAction.state = {
selectedNodeId: null,
topologyId: 'topo1',
topologyOptions: {topo1: {option1: 'on'}}
};
let nextState = initialState;
nextState = reducer(nextState, RouteAction);
expect(activeTopologyOptionsSelector(nextState).get('option1')).toBe('on');
expect(getUrlState(nextState).topologyOptions.topo1.option1).toBe('on');
// stay same after topos have been received
nextState = reducer(nextState, ReceiveTopologiesAction);
nextState = reducer(nextState, ClickTopologyAction);
expect(activeTopologyOptionsSelector(nextState).get('option1')).toBe('on');
expect(getUrlState(nextState).topologyOptions.topo1.option1).toBe('on');
});
it('uses default topology options from route', () => {
RouteAction.state = {
selectedNodeId: null,
topologyId: 'topo1',
topologyOptions: null
};
let nextState = initialState;
nextState = reducer(nextState, RouteAction);
nextState = reducer(nextState, ReceiveTopologiesAction);
nextState = reducer(nextState, ClickTopologyAction);
expect(activeTopologyOptionsSelector(nextState).get('option1')).toEqual(['off']);
expect(getUrlState(nextState).topologyOptions).toBeUndefined();
});
// nodes delta
it('replaces adjacency on update', () => {
let nextState = initialState;
nextState = reducer(nextState, ReceiveNodesDeltaAction);
expect(nextState.get('nodes').toJS().n1.adjacency).toEqual(['n1', 'n2']);
nextState = reducer(nextState, ReceiveNodesDeltaUpdateAction);
expect(nextState.get('nodes').toJS().n1.adjacency).toEqual(['n1']);
});
// browsing
it('shows nodes that were received', () => {
let nextState = initialState;
nextState = reducer(nextState, ReceiveNodesDeltaAction);
expect(nextState.get('nodes').toJS()).toEqual(NODE_SET);
});
it('knows a route was set', () => {
let nextState = initialState;
expect(nextState.get('routeSet')).toBeFalsy();
nextState = reducer(nextState, RouteAction);
expect(nextState.get('routeSet')).toBeTruthy();
});
it('gets selected node after click', () => {
let nextState = initialState;
nextState = reducer(nextState, ReceiveNodesDeltaAction);
nextState = reducer(nextState, ClickNodeAction);
expect(nextState.get('selectedNodeId')).toBe('n1');
expect(nextState.get('nodes').toJS()).toEqual(NODE_SET);
nextState = reducer(nextState, deSelectNode);
expect(nextState.get('selectedNodeId')).toBe(null);
expect(nextState.get('nodes').toJS()).toEqual(NODE_SET);
});
it('keeps showing nodes on navigating back after node click', () => {
let nextState = initialState;
nextState = reducer(nextState, ReceiveTopologiesAction);
nextState = reducer(nextState, ClickTopologyAction);
nextState = reducer(nextState, ReceiveNodesDeltaAction);
expect(getUrlState(nextState).selectedNodeId).toBeUndefined();
nextState = reducer(nextState, ClickNodeAction);
expect(getUrlState(nextState).selectedNodeId).toEqual('n1');
// go back in browsing
RouteAction.state = {selectedNodeId: null, topologyId: 'topo1'};
nextState = reducer(nextState, RouteAction);
expect(nextState.get('selectedNodeId')).toBeNull();
expect(nextState.get('nodes').toJS()).toEqual(NODE_SET);
});
it('closes details when changing topologies', () => {
let nextState = initialState;
nextState = reducer(nextState, ReceiveTopologiesAction);
nextState = reducer(nextState, ClickTopologyAction);
nextState = reducer(nextState, ReceiveNodesDeltaAction);
expect(getUrlState(nextState).selectedNodeId).toBeUndefined();
expect(getUrlState(nextState).topologyId).toEqual('topo1');
nextState = reducer(nextState, ClickNodeAction);
expect(getUrlState(nextState).selectedNodeId).toEqual('n1');
expect(getUrlState(nextState).topologyId).toEqual('topo1');
nextState = reducer(nextState, ClickSubTopologyAction);
expect(getUrlState(nextState).selectedNodeId).toBeUndefined();
expect(getUrlState(nextState).topologyId).toEqual('topo1-grouped');
});
// connection errors
it('resets topology on websocket reconnect', () => {
let nextState = initialState;
nextState = reducer(nextState, ReceiveNodesDeltaAction);
expect(nextState.get('nodes').toJS()).toEqual(NODE_SET);
nextState = reducer(nextState, CloseWebsocketAction);
expect(nextState.get('websocketClosed')).toBeTruthy();
// keep showing old nodes
expect(nextState.get('nodes').toJS()).toEqual(NODE_SET);
nextState = reducer(nextState, OpenWebsocketAction);
expect(nextState.get('websocketClosed')).toBeFalsy();
});
// adjacency test
it('returns the correct adjacency set for a node', () => {
let nextState = initialState;
nextState = reducer(nextState, ReceiveNodesDeltaAction);
expect(getAdjacentNodes(nextState).size).toEqual(0);
nextState = reducer(nextState, ClickNodeAction);
expect(getAdjacentNodes(nextState, 'n1').size).toEqual(2);
expect(getAdjacentNodes(nextState, 'n1').has('n1')).toBeTruthy();
expect(getAdjacentNodes(nextState, 'n1').has('n2')).toBeTruthy();
nextState = reducer(nextState, deSelectNode);
expect(getAdjacentNodes(nextState).size).toEqual(0);
});
// empty topology
it('detects that the nodes display is empty', () => {
let nextState = initialState;
nextState = reducer(nextState, ReceiveTopologiesAction);
nextState = reducer(nextState, ClickTopologyAction);
expect(isNodesDisplayEmpty(nextState)).toBeTruthy();
nextState = reducer(nextState, ReceiveNodesDeltaAction);
expect(isNodesDisplayEmpty(nextState)).toBeFalsy();
nextState = reducer(nextState, ClickTopology2Action);
expect(isNodesDisplayEmpty(nextState)).toBeTruthy();
nextState = reducer(nextState, ReceiveNodesDeltaAction);
expect(isNodesDisplayEmpty(nextState)).toBeFalsy();
});
it('detects that the topo stats are empty', () => {
let nextState = initialState;
nextState = reducer(nextState, ReceiveTopologiesAction);
nextState = reducer(nextState, ClickTopologyAction);
expect(isTopologyNodeCountZero(nextState)).toBeFalsy();
nextState = reducer(nextState, ReceiveNodesDeltaAction);
expect(isTopologyNodeCountZero(nextState)).toBeFalsy();
nextState = reducer(nextState, ClickTopology2Action);
expect(isTopologyNodeCountZero(nextState)).toBeTruthy();
nextState = reducer(nextState, ClickTopologyAction);
expect(isTopologyNodeCountZero(nextState)).toBeFalsy();
});
it('keeps hidden topology visible if selected', () => {
let nextState = initialState;
nextState = reducer(nextState, ReceiveTopologiesAction);
nextState = reducer(nextState, ClickTopology2Action);
nextState = reducer(nextState, ReceiveTopologiesHiddenAction);
expect(nextState.get('currentTopologyId')).toEqual('topo2');
expect(nextState.get('topologies').toJS().length).toEqual(2);
});
it('keeps hidden topology visible if sub_topology selected', () => {
let nextState = initialState;
nextState = reducer(nextState, ReceiveTopologiesAction);
nextState = reducer(nextState, { topologyId: 'topo2-sub', type: ActionTypes.CLICK_TOPOLOGY });
nextState = reducer(nextState, ReceiveTopologiesHiddenAction);
expect(nextState.get('currentTopologyId')).toEqual('topo2-sub');
expect(nextState.get('topologies').toJS().length).toEqual(2);
});
it('hides hidden topology if not selected', () => {
let nextState = initialState;
nextState = reducer(nextState, ClickTopologyAction);
nextState = reducer(nextState, ReceiveTopologiesHiddenAction);
expect(nextState.get('topologies').toJS().length).toEqual(1);
});
// selection of relatives
it('keeps relatives as a stack', () => {
let nextState = initialState;
nextState = reducer(nextState, ClickNodeAction);
expect(nextState.get('selectedNodeId')).toBe('n1');
expect(nextState.get('nodeDetails').size).toEqual(1);
expect(nextState.get('nodeDetails').has('n1')).toBeTruthy();
expect(nextState.get('nodeDetails').keySeq().last()).toEqual('n1');
nextState = reducer(nextState, ClickRelativeAction);
// stack relative, first node stays main node
expect(nextState.get('selectedNodeId')).toBe('n1');
expect(nextState.get('nodeDetails').keySeq().last()).toEqual('rel1');
expect(nextState.get('nodeDetails').size).toEqual(2);
expect(nextState.get('nodeDetails').has('rel1')).toBeTruthy();
// click on first node should clear the stack
nextState = reducer(nextState, ClickNodeAction);
expect(nextState.get('selectedNodeId')).toBe('n1');
expect(nextState.get('nodeDetails').keySeq().last()).toEqual('n1');
expect(nextState.get('nodeDetails').size).toEqual(1);
expect(nextState.get('nodeDetails').has('rel1')).toBeFalsy();
});
it('keeps clears stack when sibling is clicked', () => {
let nextState = initialState;
nextState = reducer(nextState, ClickNodeAction);
expect(nextState.get('selectedNodeId')).toBe('n1');
expect(nextState.get('nodeDetails').size).toEqual(1);
expect(nextState.get('nodeDetails').has('n1')).toBeTruthy();
expect(nextState.get('nodeDetails').keySeq().last()).toEqual('n1');
nextState = reducer(nextState, ClickRelativeAction);
// stack relative, first node stays main node
expect(nextState.get('selectedNodeId')).toBe('n1');
expect(nextState.get('nodeDetails').keySeq().last()).toEqual('rel1');
expect(nextState.get('nodeDetails').size).toEqual(2);
expect(nextState.get('nodeDetails').has('rel1')).toBeTruthy();
// click on sibling node should clear the stack
nextState = reducer(nextState, ClickNode2Action);
expect(nextState.get('selectedNodeId')).toBe('n2');
expect(nextState.get('nodeDetails').keySeq().last()).toEqual('n2');
expect(nextState.get('nodeDetails').size).toEqual(1);
expect(nextState.get('nodeDetails').has('n1')).toBeFalsy();
expect(nextState.get('nodeDetails').has('rel1')).toBeFalsy();
});
it('selectes relatives topology while keeping node selected', () => {
let nextState = initialState;
nextState = reducer(nextState, ClickTopologyAction);
nextState = reducer(nextState, ReceiveTopologiesAction);
expect(nextState.get('currentTopology').get('name')).toBe('Topo1');
nextState = reducer(nextState, ClickNodeAction);
expect(nextState.get('selectedNodeId')).toBe('n1');
expect(nextState.get('nodeDetails').size).toEqual(1);
expect(nextState.get('nodeDetails').has('n1')).toBeTruthy();
expect(nextState.get('nodeDetails').keySeq().last()).toEqual('n1');
nextState = reducer(nextState, ClickRelativeAction);
// stack relative, first node stays main node
expect(nextState.get('selectedNodeId')).toBe('n1');
expect(nextState.get('nodeDetails').keySeq().last()).toEqual('rel1');
expect(nextState.get('nodeDetails').size).toEqual(2);
expect(nextState.get('nodeDetails').has('rel1')).toBeTruthy();
// click switches over to relative's topology and selectes relative
nextState = reducer(nextState, ClickShowTopologyForNodeAction);
expect(nextState.get('selectedNodeId')).toBe('rel1');
expect(nextState.get('nodeDetails').keySeq().last()).toEqual('rel1');
expect(nextState.get('nodeDetails').size).toEqual(1);
expect(nextState.get('currentTopology').get('name')).toBe('Topo2');
});
it('closes the help dialog if the canvas is clicked', () => {
let nextState = initialState.set('showingHelp', true);
nextState = reducer(nextState, { type: ActionTypes.CLICK_BACKGROUND });
expect(nextState.get('showingHelp')).toBe(false);
});
it('switches to table view when complexity is high', () => {
let nextState = initialState.set('currentTopology', fromJS(topologies[0]));
nextState = reducer(nextState, {type: ActionTypes.SET_RECEIVED_NODES_DELTA});
expect(nextState.get('topologyViewMode')).toEqual(TABLE_VIEW_MODE);
expect(nextState.get('initialNodesLoaded')).toBe(true);
});
it('cleans up old adjacencies', () => {
// Add some nodes
const action1 = {
delta: { add: [{ id: 'n1' }, { id: 'n2' }] },
type: ActionTypes.RECEIVE_NODES_DELTA
};
// Show nodes as connected
const action2 = {
delta: {
update: [{ adjacency: ['n2'], id: 'n1' }]
},
type: ActionTypes.RECEIVE_NODES_DELTA
};
// Remove the connection
const action3 = {
delta: {
update: [{ id: 'n1' }]
},
type: ActionTypes.RECEIVE_NODES_DELTA
};
let nextState = reducer(initialState, action1);
nextState = reducer(nextState, action2);
nextState = reducer(nextState, action3);
expect(nextState.getIn(['nodes', 'n1', 'adjacency'])).toBeFalsy();
});
it('removes non-transferrable state values when changing instances', () => {
let nextState = initialState;
nextState = reducer(nextState, ClickNodeAction);
expect(nextState.get('selectedNodeId')).toEqual('n1');
expect(nextState.getIn(['nodeDetails', 'n1'])).toBeTruthy();
nextState = reducer(nextState, ChangeInstanceAction);
expect(nextState.get('selectedNodeId')).toBeFalsy();
expect(nextState.getIn(['nodeDetails', 'n1'])).toBeFalsy();
});
it('highlights bidirectional edges', () => {
const action = {
edgeId: constructEdgeId('abc123', 'def456'),
type: ActionTypes.ENTER_EDGE
};
const nextState = reducer(initialState, action);
expect(highlightedEdgeIdsSelector(nextState).toJS()).toEqual([
constructEdgeId('abc123', 'def456'),
constructEdgeId('def456', 'abc123')
]);
});
});