| test(
  'Test: phantom.bridge.LinkBridgeTest',
  [
    'ephox.agar.api.ApproxStructure',
    'ephox.agar.api.Assertions',
    'ephox.agar.api.Logger',
    'ephox.agar.api.RawAssertions',
    'ephox.alloy.test.TestStore',
    'ephox.boulder.api.FieldSchema',
    'ephox.boulder.api.Objects',
    'ephox.boulder.api.ValueSchema',
    'ephox.katamari.api.Cell',
    'ephox.katamari.api.Fun',
    'ephox.katamari.api.Option',
    'ephox.sugar.api.node.Element',
    'tinymce.themes.mobile.bridge.LinkBridge'
  ],
  function (ApproxStructure, Assertions, Logger, RawAssertions, TestStore, FieldSchema, Objects, ValueSchema, Cell, Fun, Option, Element, LinkBridge) {
    var store = TestStore();
    var editorState = {
      start: Cell(null),
      content: Cell('')
    };
    var editor = {
      selection: {
        getStart: editorState.start.get,
        getContent: editorState.content.get,
        select: Fun.noop
      },
      insertContent: function (data) {
        store.adder({ method: 'insertContent', data: data })();
      },
      execCommand: function (name) {
        store.adder({ method: 'execCommand', data: name })();
      },
      dom: {
        createHTML: function (tag, attributes, innerText) {
          return { tag: tag, attributes: attributes, innerText: innerText };
        },
        encode: Fun.identity
      },
      focus: Fun.noop
    };
    var checkGetNoLink = function (rawScenario) {
      var schema = ValueSchema.objOfOnly([
        FieldSchema.strict('label'),
        FieldSchema.defaulted('nodeText', ''),
        FieldSchema.defaulted('selection', ''),
        FieldSchema.strict('expected')
      ]);
      var scenario = ValueSchema.asRawOrDie(rawScenario.label, schema, rawScenario);
      Logger.sync('getInfo ... ' + scenario.label, function () {
        editorState.start.set(Element.fromText(scenario.nodeText).dom());
        editorState.content.set(scenario.selection);
        var info = LinkBridge.getInfo(editor);
        RawAssertions.assertEq('Checking getInfo (no link)', {
          url: '',
          text: scenario.expected,
          title: '',
          target: ''
        }, Objects.narrow(info, [ 'url', 'text', 'target', 'title' ]));
        RawAssertions.assertEq('Checking link is not set', true, info.link.isNone());
      });
    };
    var checkGetALink = function (rawScenario) {
      var schema = ValueSchema.objOfOnly([
        FieldSchema.strict('label'),
        FieldSchema.defaulted('linkHtml', ''),
        FieldSchema.defaulted('selection', ''),
        FieldSchema.strict('expected')
      ]);
      var scenario = ValueSchema.asRawOrDie(rawScenario.label, schema, rawScenario);
      Logger.sync('getInfo ... ' + scenario.label + ', link: ' + scenario.linkHtml, function () {
        editorState.start.set(Element.fromHtml(scenario.linkHtml).dom());
        editorState.content.set(scenario.selection);
        var info = LinkBridge.getInfo(editor);
        RawAssertions.assertEq('Checking getInfo (link)', scenario.expected, Objects.narrow(info, [ 'url', 'text', 'target', 'title' ]));
        RawAssertions.assertEq('Checking link is set', true, info.link.isSome());
      });
    };
    var checkApply = function (rawScenario) {
      var schema = ValueSchema.objOfOnly([
        FieldSchema.strict('label'),
        FieldSchema.strictObjOf('info', [
          FieldSchema.option('url'),
          FieldSchema.option('text'),
          FieldSchema.option('title'),
          FieldSchema.option('target'),
          FieldSchema.option('link')
        ]),
        FieldSchema.defaulted('mutations', Fun.noop),
        FieldSchema.defaulted('expected', [ ])
      ]);
      var scenario = ValueSchema.asRawOrDie(rawScenario.label, schema, rawScenario);
      Logger.sync('setInfo ... ' + scenario.label, function () {
        store.clear();
        LinkBridge.applyInfo(editor, scenario.info);
        store.assertEq('Checking store', scenario.expected);
        var link = scenario.info.link.bind(Fun.identity);
        link.each(scenario.mutations);
      });
    };
    checkGetNoLink({
      label: 'Basic text node with no text',
      expected: ''
    });
    checkGetNoLink({
      label: 'Basic text node with some text and no selection',
      nodeText: 'some',
      expected: ''
    });
    checkGetNoLink({
      label: 'Basic text node with some text and "sel" selection',
      nodeText: 'some',
      selection: 'sel',
      expected: 'sel'
    });
    checkGetALink({
      label: 'Link with href',
      linkHtml: '<a href="http://foo">Foo</a>',
      selection: 'sel',
      expected: {
        url: 'http://foo',
        text: 'Foo',
        title: '',
        target: ''
      }
    });
    checkGetALink({
      label: 'Link with href and target',
      linkHtml: '<a href="http://foo" target="_blank">Foo</a>',
      selection: 'sel',
      expected: {
        url: 'http://foo',
        text: 'Foo',
        title: '',
        target: '_blank'
      }
    });
    checkGetALink({
      label: 'Link with href and target and title',
      linkHtml: '<a href="http://foo" target="_blank" title="wow">Foo</a>',
      selection: 'sel',
      expected: {
        url: 'http://foo',
        text: 'Foo',
        title: 'wow',
        target: '_blank'
      }
    });
    checkGetALink({
      label: 'Link with href and matching text (should ignore text)',
      linkHtml: '<a href="http://foo">http://foo</a>',
      selection: 'sel',
      expected: {
        url: 'http://foo',
        text: '',
        title: '',
        target: ''
      }
    });
    checkApply({
      label: 'Applying to empty text',
      info: {
        url: 'hi'
      },
      mutations: function (elem) {
      },
      expected: [
        {
          method: 'insertContent',
          data: {
            tag: 'a',
            attributes: {
              href: 'hi'
            },
            innerText: 'hi'
          }
        }
      ]
    });
    checkApply({
      label: 'Applying to empty text with [ text ]',
      info: {
        url: 'hi',
        text: 'hello'
      },
      mutations: function (elem) {
      },
      expected: [
        {
          method: 'insertContent',
          data: {
            tag: 'a',
            attributes: {
              href: 'hi'
            },
            innerText: 'hello'
          }
        }
      ]
    });
    checkApply({
      label: 'Applying to empty text with [ text, title ]',
      info: {
        url: 'hi',
        text: 'hello',
        title: 'Title'
      },
      mutations: function (elem) {
      },
      expected: [
        {
          method: 'insertContent',
          data: {
            tag: 'a',
            attributes: {
              href: 'hi',
              title: 'Title'
            },
            innerText: 'hello'
          }
        }
      ]
    });
    checkApply({
      label: 'Applying to empty text with [ text, title, target ]',
      info: {
        url: 'hi',
        text: 'hello',
        title: 'Title',
        target: 'new'
      },
      mutations: function (elem) {
      },
      expected: [
        {
          method: 'insertContent',
          data: {
            tag: 'a',
            attributes: {
              href: 'hi',
              title: 'Title',
              target: 'new'
            },
            innerText: 'hello'
          }
        }
      ]
    });
    checkApply({
      label: 'Applying to simple link (http://foo) with url',
      info: {
        url: 'hi',
        text: '',
        title: '',
        target: '',
        link: Option.some(
          Element.fromHtml('<a href="http://foo">http://foo</a>')
        )
      },
      mutations: function (elem) {
        Assertions.assertStructure('Checking structure', ApproxStructure.build(function (s, str, arr) {
          return s.element('a', {
            attrs: {
              href: str.is('hi')
            },
            html: str.is('hi')
          });
        }), elem);
      }
    });
    checkApply({
      label: 'Applying to complex link (http://foo), Foo with url',
      info: {
        url: 'hi',
        text: '',
        title: '',
        target: '',
        link: Option.some(
          Element.fromHtml('<a href="http://foo">Foo</a>')
        )
      },
      mutations: function (elem) {
        Assertions.assertStructure('Checking structure', ApproxStructure.build(function (s, str, arr) {
          return s.element('a', {
            attrs: {
              href: str.is('hi')
            },
            html: str.is('Foo')
          });
        }), elem);
      }
    });
    checkApply({
      label: 'Applying to complex link (http://foo), Foo with url, text, and title',
      info: {
        url: 'hi',
        text: 'new-text',
        title: 'new-title',
        target: '',
        link: Option.some(
          Element.fromHtml('<a href="http://foo">Foo</a>')
        )
      },
      mutations: function (elem) {
        Assertions.assertStructure('Checking structure', ApproxStructure.build(function (s, str, arr) {
          return s.element('a', {
            attrs: {
              href: str.is('hi'),
              title: str.is('new-title')
            },
            html: str.is('new-text')
          });
        }), elem);
      }
    });
    checkApply({
      label: 'Unlinking a link by removing the URL',
      info: {
        url: '',
        text: 'new-text',
        title: 'new-title',
        target: '',
        link: Option.some(
          Element.fromHtml('<a href="http://foo">Foo</a>')
        )
      },
      expected: [
        {
          method: 'execCommand',
          data: 'unlink'
        }
      ]
    });
    checkApply({
      label: 'Unlinking should not be called if there is no existing link',
      info: {
        url: '',
        text: 'new-text',
        title: 'new-title',
        target: '',
        link: Option.none()
      },
      expected: [ ]
    });
  }
);
 |