App-Netdisco

 view release on metacpan or  search on metacpan

xt/js/netmap-autosave.test.js  view on Meta::CPAN

  path.join(repoRoot, 'share', 'views', 'js', 'netmap.js'), 'utf8');
const deviceJs = () => fs.readFileSync(
  path.join(repoRoot, 'share', 'views', 'js', 'device.js'), 'utf8');

// balanced to the handler's own closing paren, so an assertion cannot pass by
// matching text that belongs to a different handler. A line-indent heuristic
// was tried first and cut the onEngineStop body at its own fg.graphData() call.
const handlerBody = (src, name) => {
  const at = src.indexOf('.' + name + '(');
  assert.notEqual(at, -1, `netmap.js must register ${name}`);
  const open = src.indexOf('(', at);
  let depth = 0;
  for (let i = open; i < src.length; i++) {
    if (src[i] === '(') { depth++ }
    else if (src[i] === ')') { depth--; if (depth === 0) { return src.slice(open, i + 1) } }
  }
  assert.fail(`unbalanced parentheses after ${name} in netmap.js`);
};

describe('netmap autosave', () => {
  test('engineTick__while_the_simulation_runs__increments_a_counter', () => {
    const body = handlerBody(netmapJs(), 'onEngineTick');
    assert.match(
      body,
      /\+\+/,
      'the tick handler must count, or there is no way to tell a settle from an engine ' +
      'stop that ran nothing, and force-graph produces one of those per drag event. ' +
      'Count inside the existing handler: onEngineTick is a setter, so registering a ' +
      'second one would silently replace the spinner reset'
    );
  });

  test('engineStop__having_run_no_ticks__does_not_post_the_map', () => {
    const body = handlerBody(netmapJs(), 'onEngineStop');
    assert.match(
      body,
      /saveMapPositions/,
      'the settle after the first layout is still what saves it'
    );
    assert.match(
      body,
      /ticks[\s\S]{0,300}?saveMapPositions/i,
      'the save in onEngineStop must be guarded by the tick count, or every drag event ' +
      'posts the whole map again'
    );
  });

  test('nodeDragEnd__with_autosave_on__posts_the_map_once', () => {
    const body = handlerBody(netmapJs(), 'onNodeDragEnd');
    assert.match(
      body,
      /saveMapPositions/,
      'the engine stop after a drag runs no ticks, so without a save here a node the ' +
      'user moved by hand is never persisted, which the renderer this replaced did ' +
      'do'
    );
  });
});

describe('netmap autosave toggle', () => {
  // Nothing re-fetches the netmap fragment when the toggle is clicked, so a
  // value baked in at render time cannot follow it.
  test('autosaveOn__after_the_sidebar_toggle__is_read_live_not_baked_at_render', () => {
    const src = netmapJs();
    assert.doesNotMatch(
      src,
      /autosaveOn\s*=\s*\('\[%/,
      'autosave must not be baked from a template param: the toggle changes the ' +
      'checkbox without re-rendering this fragment, so a baked value cannot follow it'
    );
    assert.match(
      src,
      /getElementById\(\s*'nd_autosave'\s*\)/,
      'the autosave state must be read from the sidebar checkbox, the same way ' +
      'showips and showspeed already are in this file'
    );
  });
});

describe('netmap manual save', () => {
  test('saveMapPositions__called_by_the_button_with_autosave_off__announces', () => {
    const src = netmapJs();
    const at = src.indexOf('saveMapPositions = function');
    assert.notEqual(at, -1, 'netmap.js must define saveMapPositions');
    const body = src.slice(at, src.indexOf('\n  };', at));
    assert.match(
      body,
      /toastr\.success/,
      'a manual save has nothing else to confirm it happened, so it must say so'
    );
    assert.match(
      body,
      /if\s*\([^)]*!\s*autosaveOn[^)]*\)[\s\S]{0,120}?toastr\.success/,
      'the toast must be suppressed when autosave is on, or the map announces itself ' +
      'at every settle and every drag'
    );
    assert.match(
      body,
      /function\s*\(\s*\w+\s*\)/,
      'saveMapPositions must take the caller\'s intent as an argument: the autosave ' +
      'calls and the button call are otherwise indistinguishable from inside it'
    );
  });

  test('saveButton__on_click__tells_saveMapPositions_it_was_the_user', () => {
    const src = deviceJs();
    const at = src.indexOf("'#nd_netmap-save'");
    assert.notEqual(at, -1, 'device.js must bind the netmap Save button');
    const handler = src.slice(at, at + 260);
    assert.match(
      handler,
      /saveMapPositions\(\s*\w+/,
      'the button must pass an argument, or netmap.js cannot tell a click from the ' +
      'saves autosave makes on its own'
    );
  });
});



( run in 0.837 second using v1.01-cache-2.11-cpan-b16cb0d3907 )