UnitTest.asynctest('Browser Test: ui.SerialisedLinkTest', function () {
  const success = arguments[arguments.length - 2];
  const failure = arguments[arguments.length - 1];
  const detection = PlatformDetection.detect();

  const realm = IosRealm(Fun.noop);
  // Make toolbar appear
  Class.add(realm.system().element(), 'tinymce-mobile-fullscreen-maximized');

  const body = Body.body();
  Attachment.attachSystem(body, realm.system());

  const doc = Traverse.owner(body);

  TestStyles.addStyles();

  const unload = function () {
    TestStyles.removeStyles();
    Attachment.detachSystem(realm.system());
  };

  const tEditor = TestEditor();

  realm.setToolbarGroups([
    {
      label: 'group1',
      items: [
        LinkButton.sketch(realm, tEditor.editor())
      ]
    }
  ]);

  const sAssertNavigation = function (label, prevEnabled, nextEnabled) {
    return Logger.t(
      label,
      Step.sync(function () {
        const active = Focus.active().getOrDie();
        // The buttons are next and previous siblings
        const prev = Traverse.parent(active).bind(Traverse.prevSibling).getOrDie('Could not find button to left');
        const next = Traverse.parent(active).bind(Traverse.nextSibling).getOrDie('Could not find button to right');

        const assertNavButton = function (buttonLabel, expected, button) {
          Assertions.assertStructure(
            'Checking ' + buttonLabel + ' button should be enabled = ' + expected,
            ApproxStructure.build(function (s, str, arr) {
              return s.element('span', {
                attrs: {
                  role: str.is('button')
                },
                classes: [
                  (expected ? arr.not : arr.has)('tinymce-mobile-toolbar-navigation-disabled')
                ]
              });
            }),
            button
          );
        };

        assertNavButton('previous', prevEnabled, prev);
        assertNavButton('next', nextEnabled, next);
      })
    );
  };

  const sClickNavigation = function (selector) {
    return Chain.asStep({ }, [
      TestUi.cGetFocused,
      TestUi.cGetParent,
      TestUi.cGetParent,
      UiFinder.cFindIn(selector),
      Mouse.cClick
    ]);
  };

  const sClickPrev = sClickNavigation('.tinymce-mobile-icon-previous');
  const sClickNext = sClickNavigation('.tinymce-mobile-icon-next');

  const sAssertUrlFocused = GeneralSteps.sequence([
    FocusTools.sTryOnSelector('Focus should be on input with link URL', doc, 'input[placeholder="Type or paste URL"]'),
    sAssertNavigation('Checking initial navigation on text node', false, true)
  ]);

  const sAssertTextFocused = GeneralSteps.sequence([
    FocusTools.sTryOnSelector('Focus should be on input with link text', doc, 'input[placeholder="Link text"]'),
    sAssertNavigation('Checking navigation for link text', true, true)
  ]);

  const sAssertTitleFocused = GeneralSteps.sequence([
    FocusTools.sTryOnSelector('Focus should be on input with link title', doc, 'input[placeholder="Link title"]'),
    sAssertNavigation('Checking navigation for link title', true, true)
  ]);

  const sAssertTargetFocused = GeneralSteps.sequence([
    FocusTools.sTryOnSelector('Focus should be on input with link target', doc, 'input[placeholder="Link target"]'),
    sAssertNavigation('Checking navigation for link target', true, false)
  ]);

  const sTestNavigation = GeneralSteps.sequence([
    Keyboard.sKeydown(doc, Keys.tab(), { }),
    sAssertTextFocused,
    Keyboard.sKeydown(doc, Keys.tab(), { }),
    sAssertTitleFocused,
    Keyboard.sKeydown(doc, Keys.tab(), { }),
    sAssertTargetFocused,
    Keyboard.sKeydown(doc, Keys.tab(), { shift: true }),
    sAssertTitleFocused,
    Keyboard.sKeydown(doc, Keys.tab(), { shift: false }),
    sAssertTargetFocused,
    Keyboard.sKeydown(doc, Keys.tab(), { }),

    Step.wait(1000),
    Logger.t('Checking pressing tab at the end should not move focus', sAssertTargetFocused),

    sClickPrev,
    sAssertTitleFocused,
    sClickNext,
    sAssertTargetFocused,
    sClickPrev,
    sAssertTitleFocused,
    sClickPrev,
    sAssertTextFocused,
    sClickPrev,
    sAssertUrlFocused
  ]);

  const sClickLink = Mouse.sClickOn(realm.element(), TestSelectors.link());

  const sTestScenario = function (rawScenario) {
    const scenario = ValueSchema.asRawOrDie('Checking scenario', ValueSchema.objOf([
      FieldSchema.strict('label'),
      FieldSchema.defaulted('content', ''),
      FieldSchema.defaulted('node', Element.fromText('')),
      FieldSchema.strictObjOf('fields', [
        FieldSchema.option('url'),
        FieldSchema.option('text'),
        FieldSchema.option('title'),
        FieldSchema.option('target')
      ]),
      FieldSchema.strict('expected'),
      FieldSchema.defaulted('beforeExecute', Step.pass),
      FieldSchema.defaulted('mutations', Fun.constant(Step.pass))
    ]), rawScenario);

    return Logger.t(
      scenario.label,
      GeneralSteps.sequence([
        tEditor.sPrepareState(scenario.node.dom(), scenario.content),
        sClickLink,
        TestUi.sSetFieldOptValue(scenario.fields.url),
        sClickNext,
        sAssertTextFocused,
        TestUi.sSetFieldOptValue(scenario.fields.text),
        sClickNext,
        sAssertTitleFocused,
        TestUi.sSetFieldOptValue(scenario.fields.title),
        sClickNext,
        sAssertTargetFocused,
        TestUi.sSetFieldOptValue(scenario.fields.target),
        sClickPrev,
        sAssertTitleFocused,
        sClickPrev,
        sAssertTextFocused,
        sClickPrev,
        sAssertUrlFocused,
        scenario.beforeExecute,
        Keyboard.sKeydown(doc, Keys.enter(), { }),
        tEditor.sAssertEq('Checking insert content', scenario.expected),
        scenario.mutations(scenario.node),
        tEditor.sClear

      ])
    );
  };

  Pipeline.async({}, detection.browser.isChrome() ? [
    GuiSetup.mAddStyles(doc, [
      '.tinymce-mobile-icon-link:before { content: "LINK"; background: black; color: white; }',
      // Speeds up tests.
      '.tinymce-mobile-serialised-dialog-chain { transition: left linear 0.000001s !important }'
    ]),

    TestStyles.sWaitForToolstrip(realm),

    tEditor.sPrepareState(Element.fromText('hi'), 'link-text'),

    sClickLink,
    FocusTools.sTryOnSelector('Focus should be on input with link URL', doc, 'input[placeholder="Type or paste URL"]'),
    sAssertNavigation('Checking initial navigation on text node', false, true),

    sTestNavigation,
    Step.sync(function () {
      realm.restoreToolbar();
    }),

    sTestScenario({
      label: 'Testing hitting ENTER after just setting URL',
      fields: {
        url: 'http://fake-url'
      },
      expected: [
        {
          method: 'insertContent',
          data: {
            tag: 'a',
            attributes: {
              href: 'http://fake-url'
            },
            innerText: 'http://fake-url'
          }
        }
      ]
    }),

    sTestScenario({
      label: 'Testing hitting ENTER after filling in URL and text',
      fields: {
        url: 'http://fake-url',
        text: 'LinkText'
      },
      expected: [
        {
          method: 'insertContent',
          data: {
            tag: 'a',
            attributes: {
              href: 'http://fake-url'
            },
            innerText: 'LinkText'
          }
        }
      ]
    }),

    sTestScenario({
      label: 'Testing hitting ENTER after filling in URL and title (not text)',
      fields: {
        url: 'http://fake-url',
        title: 'Title'
      },
      expected: [
        {
          method: 'insertContent',
          data: {
            tag: 'a',
            attributes: {
              href: 'http://fake-url',
              title: 'Title'
            },
            innerText: 'http://fake-url'
          }
        }
      ]
    }),

    sTestScenario({
      label: 'Testing hitting ENTER after filling in URL, text, and title',
      fields: {
        url: 'http://fake-url',
        text: 'LinkText',
        title: 'Title'
      },
      expected: [
        {
          method: 'insertContent',
          data: {
            tag: 'a',
            attributes: {
              href: 'http://fake-url',
              title: 'Title'
            },
            innerText: 'LinkText'
          }
        }
      ]
    }),

    sTestScenario({
      label: 'Testing hitting ENTER after filling in URL, text, title, and target',
      fields: {
        url: 'http://fake-url',
        text: 'LinkText',
        title: 'Title',
        target: 'Target'
      },
      expected: [
        {
          method: 'insertContent',
          data: {
            tag: 'a',
            attributes: {
              href: 'http://fake-url',
              title: 'Title',
              target: 'Target'
            },
            innerText: 'LinkText'
          }
        }
      ]
    }),

    sTestScenario({
      label: 'Testing hitting ENTER after filling in URL with initial text selection',
      content: 'Initial text selection',
      fields: {
        url: 'http://fake-url'
      },
      expected: [
        {
          method: 'insertContent',
          data: {
            tag: 'a',
            attributes: {
              href: 'http://fake-url'
            },
            innerText: 'Initial text selection'
          }
        }
      ]
    }),

    sTestScenario({
      label: 'Testing hitting ENTER after filling in nothing with an existing link with url',
      node: Element.fromHtml('<a href="http://prepared-url">Prepared</a>'),
      fields: { },
      expected: [ ],
      mutations (node) {
        return Assertions.sAssertStructure('Checking mutated structure', ApproxStructure.build(function (s, str, arr) {
          return s.element('a', {
            attrs: {
              href: str.is('http://prepared-url')
            },
            html: str.is('Prepared')
          });
        }), node);
      }
    }),

    sTestScenario({
      label: 'Testing hitting ENTER after filling in URL with an existing link with url (and text content did not match URL previously)',
      node: Element.fromHtml('<a href="http://prepared-url">Prepared</a>'),
      fields: {
        url: 'http://new-url'
      },
      expected: [ ],
      mutations (node) {
        return Assertions.sAssertStructure('Checking mutated structure', ApproxStructure.build(function (s, str, arr) {
          return s.element('a', {
            attrs: {
              href: str.is('http://new-url')
            },
            html: str.is('Prepared')
          });
        }), node);
      }
    }),

    sTestScenario({
      label: 'Testing hitting ENTER after filling in URL with an existing link with url (and text content matched URL previously)',
      node: Element.fromHtml('<a href="http://prepared-url">http://prepared-url</a>'),
      fields: {
        url: 'http://new-url'
      },
      expected: [ ],
      mutations (node) {
        return Assertions.sAssertStructure('Checking mutated structure', ApproxStructure.build(function (s, str, arr) {
          return s.element('a', {
            attrs: {
              href: str.is('http://new-url')
            },
            html: str.is('http://new-url')
          });
        }), node);
      }
    }),

    sTestScenario({
      label: 'Testing hitting ENTER after filling in URL and text with an existing link with url',
      node: Element.fromHtml('<a href="http://prepared-url">any text</a>'),
      fields: {
        url: 'http://new-url',
        text: 'new-text'
      },
      expected: [ ],
      mutations (node) {
        return Assertions.sAssertStructure('Checking mutated structure', ApproxStructure.build(function (s, str, arr) {
          return s.element('a', {
            attrs: {
              href: str.is('http://new-url')
            },
            html: str.is('new-text')
          });
        }), node);
      }
    })
  ] : [], function () {
    unload(); success();
  }, failure);
});
 const assertRange = function (expected, actual) {
   Assertions.assertEq('startContainers should be equal', true, expected.startContainer === actual.startContainer);
   Assertions.assertEq('startOffset should be equal', true, expected.startOffset === actual.startOffset);
   Assertions.assertEq('endContainer should be equal', true, expected.endContainer === actual.endContainer);
   Assertions.assertEq('endOffset should be equal', true, expected.endOffset === actual.endOffset);
 };
Example #3
0
 return Step.sync(() => {
   const returnVal = TableDelete.backspaceDelete(editor, false);
   Assertions.assertEq('Should return true since the operation should have done something', true, returnVal);
 });
Example #4
0
    (doc, body, gui, component, store) => {

      const input = component.getSystem().getByDom(
        SelectorFind.descendant(component.element(), 'input').getOrDie(
          'Could not find input'
        )
      ).getOrDie();

      return [
        TestHelpers.GuiSetup.mAddStyles(doc, [
          '.tox-menu { background: white; }',
          '.tox-collection__item--active { background: #cadbee }'
        ]),

        Step.sync(() => {
          Focusing.focus(input);
        }),
        Keyboard.sKeydown(doc, Keys.down(), { }),

        Waiter.sTryUntil(
          'Waiting for menu to appear',
          UiFinder.sExists(
            sink,
            '.tox-menu .tox-collection__item'
          ),
          100,
          4000
        ),

        Chain.asStep(sink, [
          UiFinder.cFindIn('[role="menu"]'),
          Assertions.cAssertStructure(
            'Checking structure of menu (especially text)',
            ApproxStructure.build((s, str, arr) => {
              return s.element('div', {
                classes: [ arr.has('tox-menu'), arr.has('tox-collection--list'), arr.has('tox-collection') ],
                children: [
                  s.element('div', {
                    classes: [ arr.has('tox-collection__group') ],
                    children: [
                      s.element('div', {
                        classes: [ arr.has('tox-collection__item')],
                        children: [
                          s.element('div', { html: str.is('Header1') })
                        ]
                      }),
                      s.element('div', {
                        classes: [ arr.has('tox-collection__item')],
                        children: [
                          s.element('div', { html: str.is('Header2') })
                        ]
                      })
                    ]
                  }),
                  s.element('div', {
                    classes: [ arr.has('tox-collection__group') ],
                    children: [
                      s.element('div', {
                        children: [
                          s.element('div', { html: str.is('&lt;top&gt;') })
                        ]
                      })
                    ]
                  })
                ]
              });
            })
          )
        ]),

        UiControls.sSetValue(input.element(), 'He'),
        Step.sync(() => {
          AlloyTriggers.emit(input, NativeEvents.input());
        }),
        Waiter.sTryUntil(
          'Waiting for the menu to update',
          Chain.asStep(sink, [
            UiFinder.cFindAllIn('.tox-collection__item'),
            Chain.op((menuItems) => {
              if (menuItems.length > 2) {
                throw Error('Menu hasn\'t been updated yet');
              }
            })
          ]),
          100,
          3000
        ),
        Chain.asStep(sink, [
          UiFinder.cFindIn('[role="menu"]'),
          Assertions.cAssertStructure(
            'Checking the menu shows items that match the input string',
            ApproxStructure.build((s, str, arr) => {
              return s.element('div', {
                classes: [ arr.has('tox-menu'), arr.has('tox-collection--list'), arr.has('tox-collection') ],
                children: [
                  s.element('div', {
                    classes: [ arr.has('tox-collection__group') ],
                    children: [
                      s.element('div', {
                        classes: [ arr.has('tox-collection__item')],
                        children: [
                          s.element('div', { html: str.is('Header1') })
                        ]
                      }),
                      s.element('div', {
                        classes: [ arr.has('tox-collection__item')],
                        children: [
                          s.element('div', { html: str.is('Header2') })
                        ]
                      })
                    ]
                  })
                ]
              });
            })
          )
        ]),

        store.sAssertEq('nothing in store ... before selecting item', []),
        Keyboard.sKeydown(doc, Keys.enter(), { }),
        Step.sync(() => {
          Assertions.assertEq('Checking Value.get', '#header', Value.get(input.element()));
          const repValue = Representing.getValue(input);
          Assertions.assertEq('Checking Rep.getValue',
            {
              value: '#header',
              meta: { text: 'Header1' }
            },
            {
              value: repValue.value,
              meta: { text: repValue.meta.text }
            }
          );
        }),

        store.sAssertEq('addToHistory called ... before firing attach', [ 'addToHistory' ]),
        Logger.t(
          'Check that attach fires',
          Step.sync(() => {
            const repValue = Representing.getValue(input);
            repValue.meta.attach();
          })
        ),
        store.sAssertEq('Attach should be in store ... after firing attach', [ 'addToHistory' , 'header1.attach' ]),

        Mouse.sClickOn(component.element(), 'button'),

        store.sAssertEq(
          'URL picker should have been opened ... after clicking button',
          [ 'addToHistory' , 'header1.attach', 'urlpicker' ]
        ),

        Waiter.sTryUntilPredicate('Checking Value.get', () => {
          return 'http://tiny.cloud' === Value.get(input.element());
        }, 100, 4000),

        Step.sync(() => {
          const repValue = Representing.getValue(input);
          Assertions.assertEq('Checking Rep.getValue', {
            value: 'http://tiny.cloud',
            meta: { before: '#header'}
          }, repValue);
        }),

        TestHelpers.GuiSetup.mRemoveStyles
      ];
    }, () => {
Example #5
0
 Chain.op((menu) => {
   const checkMarks = Selectors.all('.tox-collection__item-icon');
   Assertions.assertEq('only one check mark is displayed for active toggled menu items', 1, checkMarks.length);
 })
 }).then(function (result) {
   Assertions.assertEq('Should be an result that is zero length', 0, result.length);
   teardown(done);
 });
Example #7
0
 return Step.sync(function () {
   const returnVal = BlockRangeDelete.backspaceDelete(editor, false);
   Assertions.assertEq('Should return true since the operation should have done something', true, returnVal);
 });
Example #8
0
 return Chain.op(function (data: any) {
   Assertions.assertStructure('', structure, data.parent);
 });
Example #9
0
 Step.sync(function () {
   const toolstrip = iframe.dom().contentWindow.document.querySelector('.tinymce-mobile-toolstrip');
   Assertions.assertEq('Checking that the toolstrip is off screen when window moves', true, toolstrip.getBoundingClientRect().top < 0);
 }),
Example #10
0
 const sAssertPresense = function (selector) {
   return Assertions.sAssertPresence('Detect presense of the element', selector, TinyDom.fromDom(editor.getBody()));
 };
Example #11
0
 return Step.sync(function () {
   const countEl = DOMUtils.DOM.select('.mce-wordcount')[0];
   const value = countEl ? countEl.innerText : '';
   Assertions.assertEq('wordcount', num + ' WORDS', value.toUpperCase());
 });
Example #12
0
 const check = function (label, expected, toolbar) {
   const actual = Features.detect({ toolbar }, features);
   Assertions.assertEq(label, expected, actual);
 };
Example #13
0
 return Step.sync(function () {
   const elm = createViewElement(html);
   const position = createPosition(elm, elementPath, offset);
   const location = BoundaryLocation.findLocation(forward, isInlineTarget, elm.dom(), position);
   Assertions.assertEq('Should not be a valid location: ' + html, true, location.isNone());
 });
Example #14
0
 return Step.sync(function () {
   const elm = createViewElement(html);
   const location = createLocation(elm, elementPath, offset);
   Assertions.assertEq('Should not be a valid location: ' + html, true, location.isNone());
 });
Example #15
0
 return Chain.op(function (tableModel) {
   const actualHtml = Html.getOuter(SimpleTableModel.toDom(tableModel));
   Assertions.assertHtml('Should be expected table html', expectedHtml, actualHtml);
 });
Example #16
0
 Step.sync(function () {
   const toolstrip = iframe.dom().contentWindow.document.querySelector('.tinymce-mobile-toolstrip');
   Assertions.assertEq('Checking that the toolstrip is at top of screen after scroll recognised', 0, toolstrip.getBoundingClientRect().top);
 }),
 Arr.each(targets, function (target) {
   Assertions.assertEq('Target parent should not be null', true, target.parentNode !== null);
 });
Example #18
0
 Step.stateful(function (value, next, die) {
   const nowCursorY = getCursorY(value.target);
   Assertions.assertEq('Checking visual position values are approximately equal after scrolling', true, Math.abs(nowCursorY - value.cursorY) < 10);
   next(value);
 })
 return Chain.op(function (cells: Element[]) {
   const actualContents = Arr.map(cells, Html.get);
   Assertions.assertEq('Should be expected cell contents', expectedContents, actualContents);
 });
Example #20
0
 return Chain.op(function (editor: any) {
   Assertions.assertHtml('Checking TinyMCE content', expected, editor.getContent());
 });
Example #21
0
 return Step.sync(function () {
   const returnVal = BlockRangeDelete.backspaceDelete(editor, false);
   Assertions.assertEq('Should return false since the operation is a noop', false, returnVal);
 });
Example #22
0
 Step.sync(() => {
   const c = Composing.getCurrent(component).getOrDie('Trying to get the composed component');
   Assertions.assertEq('Representing value', expected, Representing.getValue(c));
 })
Example #23
0
    (doc, body, gui, testContainer, store) => {
      const menubarEl = SelectorFind.descendant(testContainer.element(), '.test-menubar').getOrDie('Could not find menubar to test');

      const menubar = testContainer.getSystem().getByDom(menubarEl).getOrDie();

      const sAssertFocusOnToggleItem = (itemText: string) =>
        FocusTools.sTryOnSelector(
          'Focus should be on a toggle menu item containing: ' + itemText,
          doc,
          '.tox-selected-menu [role=menuitemcheckbox]:contains("' + itemText + '")'
        );

      const sAssertActiveToggleItemHasOneCheckmark = (itemText: string) =>
        Chain.asStep(sink, [
          UiFinder.cFindIn('.tox-selected-menu [role=menuitemcheckbox]:contains("' + itemText + '")'),
          Chain.op((menu) => {
            const checkMarks = Selectors.all('.tox-collection__item-icon');
            Assertions.assertEq('only one check mark is displayed for active toggled menu items', 1, checkMarks.length);
          })
        ]);

      const sAssertFocusOnItem = (itemText: string) =>
        FocusTools.sTryOnSelector(
          'Focus should be on item containing: ' + itemText,
          doc,
          '.tox-selected-menu [role=menuitem]:contains("' + itemText + '")'
        );

      const sAssertFocusOnMenuButton = (buttonText: string) =>
        FocusTools.sTryOnSelector(
          'Focus should be on menubar button containing: ' + buttonText,
          doc,
          '[role=menubar] button[role=menuitem]:contains("' + buttonText + '")'
        );

      const sWaitForMenuToAppear = () =>
        // Wait for menu to appear
        Waiter.sTryUntil(
          'Waiting for menu to be in DOM',
          UiFinder.sExists(sink, '.tox-menu'),
          100,
          1000
        );

      const sWaitForMenuToDisappear = () =>
        Waiter.sTryUntil(
          'Waiting for menu to NO LONGER be in DOM',
          UiFinder.sNotExists(sink, '.tox-menu'),
          100,
          1000
        );

      const sAssertMenuItemGroups = (label: string, groups: string[][]) => Logger.t(
        label,
        Chain.asStep(sink, [
          UiFinder.cFindIn('.tox-selected-menu'),
          Assertions.cAssertStructure(
            'Checking contents of menu',
            ApproxStructure.build((s, str, arr) => {
              return s.element('div', {
                children: Arr.map(groups, (items) => {
                  return s.element('div', {
                    classes: [ arr.has('tox-collection__group') ],
                    children: Arr.map(items, (itemText) => {
                      // itemText can have a trailing >, which means it has a caret
                      const hasCaret = Strings.endsWith(itemText, '>');
                      return s.element('div', {
                        classes: [ arr.has('tox-collection__item') ],
                        children: [
                          s.element('div', { classes: [ arr.has('tox-collection__item-icon') ] }),
                          s.element('div', {
                            classes: [ arr.has('tox-collection__item-label') ],
                            html: str.is(hasCaret ? itemText.substring(0, itemText.length - 1) : itemText)
                          })
                        ].concat(hasCaret ? [
                          s.element('div', { classes: [ arr.has('tox-collection__item-caret') ] })
                        ] : [ ])
                      });
                    })
                  });
                })
              });
            })
          )
        ])
      );

      return [
        store.sAssertEq('setup should have been called', [ 'Menubar.setup' ]),
        store.sClear,
        Assertions.sAssertStructure(
          'Checking initial structure for menubar',
          ApproxStructure.build((s, str, arr) => {
            return s.element('div', {
              classes: [arr.has('test-menubar')],
              attrs: {
                role: str.is('menubar')
              },
              children: [ ]
            });
          }),
          menubar.element()
        ),

        Logger.t(
          'Setup some menubar groups',
          Step.sync(() => {
            SilverMenubar.setMenus(menubar, [
              {
                text: 'Changes',
                getItems: () => [
                  {
                    type: 'togglemenuitem',
                    text: 'Remember me',
                    onAction: store.adder('remember.me'),
                    onSetup: (api) => {
                      // Set twice to check for a bug where two checkmarks appear
                      api.setActive(true);
                      api.setActive(true);
                      return Fun.noop;
                    }
                  }
                ]
              },
              {
                text: 'Basic Menu Button',
                getItems: () => [
                  {
                    type: 'menuitem',
                    text: 'Item1',
                    icon: 'drop',
                    onAction: store.adder('menuitem-1-action')
                  },
                  {
                    type: 'separator'
                  },
                  {
                    type: 'menuitem',
                    icon: 'drop',
                    text: 'Item2',
                    onAction: () => {
                      store.adder('menuitem-2 action')();
                    }
                  },
                  {
                    type: 'nestedmenuitem',
                    icon: 'drop',
                    text: 'Nested menu',
                    getSubmenuItems: () => [
                      {
                        type: 'nestedmenuitem',
                        icon: 'drop',
                        text: 'Nested menu x 2',
                        getSubmenuItems: () => [
                          {
                            type: 'menuitem',
                            icon: 'drop',
                            text: 'Nested menu x 3',
                            onAction: () => { }
                          }
                        ]
                      }
                    ]
                  }
                ]
              }
            ]);
          })
        ),

        Step.sync(() => {
          SilverMenubar.focus(menubar);
        }),

        sAssertFocusOnMenuButton('Changes'),
        Keyboard.sKeydown(doc, Keys.space(), { }),
        sWaitForMenuToAppear(),
        sAssertFocusOnToggleItem('Remember me'),
        sAssertActiveToggleItemHasOneCheckmark('Remember me'),
        Keyboard.sKeydown(doc, Keys.escape(), { }),
        sAssertFocusOnMenuButton('Changes'),
        sWaitForMenuToDisappear(),

        Keyboard.sKeydown(doc, Keys.right(), {}),
        sAssertFocusOnMenuButton('Basic Menu Button'),

        Keyboard.sKeydown(doc, Keys.space(), { }),
        sWaitForMenuToAppear(),
        sAssertFocusOnItem('Item1'),

        Keyboard.sKeydown(doc, Keys.down(), { }),
        sAssertFocusOnItem('Item2'),

        Keyboard.sKeydown(doc, Keys.down(), { }),
        sAssertFocusOnItem('Nested'),

        Keyboard.sKeydown(doc, Keys.right(), { }),
        sAssertFocusOnItem('Nested menu x 2'),

        Keyboard.sKeydown(doc, Keys.right(), { }),
        sAssertFocusOnItem('Nested menu x 3'),

        Keyboard.sKeydown(doc, Keys.left(), { }),
        sAssertFocusOnItem('Nested menu x 2'),

        Keyboard.sKeydown(doc, Keys.escape(), { }),
        sAssertFocusOnItem('Nested'),

        Keyboard.sKeydown(doc, Keys.escape(), { }),
        sAssertFocusOnMenuButton('Basic Menu Button'),
        sWaitForMenuToDisappear(),

        Keyboard.sKeydown(doc, Keys.enter(), { }),
        sWaitForMenuToAppear(),
        sAssertFocusOnItem('Item1'),

        Keyboard.sKeydown(doc, Keys.up(), { }),
        sAssertFocusOnItem('Nested'),
        Keyboard.sKeydown(doc, Keys.enter(), { }),
        sAssertFocusOnItem('Nested menu x 2'),

        Keyboard.sKeydown(doc, Keys.escape(), { }),
        sAssertFocusOnItem('Nested'),
        Keyboard.sKeydown(doc, Keys.up(), { }),
        Keyboard.sKeydown(doc, Keys.enter(), { }),
        Logger.t(
          'Pressing <enter> on an item without a submenu should trigger it and close the menu',
          GeneralSteps.sequence([
            sWaitForMenuToDisappear(),
            store.sAssertEq('Store should have evidence of item triggered', [ 'menuitem-2 action' ])
          ])
        ),

        store.sClear,
        Step.sync(() => {
          SilverMenubar.focus(menubar);
        }),
        sAssertFocusOnMenuButton('Changes'),

        Keyboard.sKeydown(doc, Keys.escape(), { }),
        store.sAssertEq('Pressing escape in menubar should fire event', [ 'Menubar.escape' ]),

        Log.stepsAsStep('TBA', 'AP-307: Once a menu is expanded, hovering on buttons should switch which menu is expanded', [
          Mouse.sHoverOn(menubar.element(), 'button[role="menuitem"]:contains("Basic Menu Button")'),
          Step.wait(100),
          UiFinder.sNotExists(sink, '[role="menu"]'),
          Mouse.sClickOn(menubar.element(), 'button[role="menuitem"]:contains("Changes")'),
          UiFinder.sWaitForVisible(
            'Waiting for changes menu',
            sink,
            '.tox-collection__item:contains("Remember me")'
          ),
          sAssertMenuItemGroups('After clicking on "Changes"', [
            [ 'Remember me' ]
          ]),
          Mouse.sHoverOn(menubar.element(), 'button[role="menuitem"]:contains("Basic Menu Button")'),
          UiFinder.sWaitForVisible(
            'Waiting for basic menu',
            sink,
            '.tox-collection__item:contains("Item1")'
          ),
          // Focus the menu item, not the toolbar item
          Keyboard.sKeydown(doc, Keys.down(), { }),
          UiFinder.sWaitForVisible(
            'Wait for basic menu to get selected class',
            sink,
            '.tox-selected-menu .tox-collection__item:contains("Item1")'
          ),
          // This is failing because tox-selected-menu is not set.
          sAssertMenuItemGroups('After hovering on Basic (after another menu was open)', [
            [ 'Item1' ],
            [ 'Item2', 'Nested menu>' ]
          ])
        ])
      ];
    }, () => {
 return Step.sync(function () {
   Assertions.assertEq('Should have the right caret data', expectedCaretData, editor.selection.getNode().getAttribute('data-mce-caret'));
 });
 getDialogByElement(element).fold(() => die('No dialog assocated with element'), function (win) {
   Assertions.assertEq('asserting dialog contents', data, win.toJSON());
   next(element);
 });
Example #26
0
 return Chain.op(function (tableModel) {
   Assertions.assertEq('Should be expected width', expectedWidth, tableModel.width());
 });
Example #27
0
 Step.sync(function () {
   Assertions.assertEq('Styles added to iframe document', 'right', editor.dom.getStyle(editor.getBody().firstChild, 'text-align', true));
 }
Example #28
0
 return Chain.op(function (tableModel) {
   Assertions.assertEq('Should be expected height', expectedWidth, tableModel.rows().length);
 });
Example #29
0
 return Step.sync(() => {
   const returnVal = TableDelete.backspaceDelete(editor, true);
   Assertions.assertEq('Should return false since the operation is a noop', false, returnVal);
 });
  TinyLoader.setup(function (editor, onSuccess, onFailure) {
    const tinyApis = TinyApis(editor);
    const root = Element.fromDom(editor.getBody());

    Pipeline.async({}, [
      Logger.t('Should insert a before b', GeneralSteps.sequence([
        tinyApis.sSetContent('<p>b</p>'),
        tinyApis.sSetSelection([0, 0], 0, [0, 0], 0),
        sSetContent(editor, 'a', {}),
        tinyApis.sAssertContent('<p>ab</p>')
      ])),
      Logger.t('Should fill the body with x h1 instead of a before b in a paragraph', GeneralSteps.sequence([
        tinyApis.sSetContent('<p>b</p>'),
        tinyApis.sSetSelection([0, 0], 0, [0, 0], 0),
        sSetContentOverride(editor, 'a', '<h1>x</h1>', {}),
        tinyApis.sAssertContent('<h1>x</h1>')
      ])),

      Logger.t('Insert content in middle of word, expanded selection', GeneralSteps.sequence([
        tinyApis.sSetContent('<p>abc</p>'),
        tinyApis.sSetSelection([0, 0], 1, [0, 0], 2),
        sSetContent(editor, 'X', {}),
        Assertions.sAssertStructure('Checking initial structure',
          ApproxStructure.build((s, str, arr) => {
            return s.element('body', {
              children: [
                s.element('p', {
                  children: [
                    s.text(str.is('aXc'))
                  ]
                })
              ]
            });
          }),
          root
        ),
        tinyApis.sAssertSelection([0, 0], 2, [0, 0], 2),
      ])),

      Logger.t('Insert content in middle of word, collapsed selection', GeneralSteps.sequence([
        tinyApis.sSetContent('<p>ab</p>'),
        tinyApis.sSetSelection([0, 0], 1, [0, 0], 1),
        sSetContent(editor, 'X', {}),
        Assertions.sAssertStructure('Checking initial structure',
          ApproxStructure.build((s, str, arr) => {
            return s.element('body', {
              children: [
                s.element('p', {
                  children: [
                    s.text(str.is('aXb'))
                  ]
                })
              ]
            });
          }),
          root
        ),
        tinyApis.sAssertSelection([0, 0], 2, [0, 0], 2),
      ])),

      Logger.t('Insert content at start of word, collapsed selection', GeneralSteps.sequence([
        tinyApis.sSetContent('<p>a</p>'),
        tinyApis.sSetSelection([0, 0], 0, [0, 0], 0),
        sSetContent(editor, 'X', {}),
        Assertions.sAssertStructure('Checking initial structure',
          ApproxStructure.build((s, str, arr) => {
            return s.element('body', {
              children: [
                s.element('p', {
                  children: [
                    s.text(str.is('Xa'))
                  ]
                })
              ]
            });
          }),
          root
        ),
        tinyApis.sAssertSelection([0, 0], 1, [0, 0], 1),
      ])),

      Logger.t('Insert content at end of word, collapsed selection', GeneralSteps.sequence([
        tinyApis.sSetContent('<p>a</p>'),
        tinyApis.sSetSelection([0, 0], 1, [0, 0], 1),
        sSetContent(editor, 'X', {}),
        Assertions.sAssertStructure('Checking initial structure',
          ApproxStructure.build((s, str, arr) => {
            return s.element('body', {
              children: [
                s.element('p', {
                  children: [
                    s.text(str.is('aX'))
                  ]
                })
              ]
            });
          }),
          root
        ),
      ])),

      Logger.t('Insert content at end of word with partial text', GeneralSteps.sequence([
        tinyApis.sSetContent('<p>a</p>'),
        tinyApis.sSetSelection([0, 0], 1, [0, 0], 1),
        sSetContent(editor, 'b<em>c</em>', {}),
        Assertions.sAssertStructure('Checking initial structure',
          ApproxStructure.build((s, str, arr) => {
            return s.element('body', {
              children: [
                s.element('p', {
                  children: [
                    s.text(str.is('ab')),
                    s.element('em', {
                      children: [
                        s.text(str.is('c'))
                      ]
                    })
                  ]
                })
              ]
            });
          }),
          root
        ),
      ])),

      Logger.t('Insert content at end of word with partial text', GeneralSteps.sequence([
        tinyApis.sSetContent('<p>a</p>'),
        tinyApis.sSetSelection([0, 0], 1, [0, 0], 1),
        sSetContent(editor, '<em>b</em>c', {}),
        Assertions.sAssertStructure('Checking initial structure',
          ApproxStructure.build((s, str, arr) => {
            return s.element('body', {
              children: [
                s.element('p', {
                  children: [
                    s.text(str.is('a')),
                    s.element('em', {
                      children: [
                        s.text(str.is('b'))
                      ]
                    }),
                    s.text(str.is('c'))
                  ]
                })
              ]
            });
          }),
          root
        ),
      ])),
    ], onSuccess, onFailure);
  }, {