text: /**
   * The testScenarios object is for testing a wide range of jQuery UI position
   * configuration options. The object properties are:
   * {
   *   - How the `of:` option will be used. This option determines the element the
   *     positioned element will attach to. This can be a selector, window, a
   *     jQuery object, or a vanilla JS element.
   *     - `my`: Sets the 'my' option for position().
   *     - `at`: Sets the 'at' option for position().
   *     - `x`: The expected X position of the element being positioned.
   *     - `y`: The expected Y position of the element being positioned.
   * }
   * This covers every possible combination of `my:` and `at:` using fixed amounts
   * (left, right, center, top, bottom), with additional scenarios that include
   * offsets.
   */
  /* cSpell:disable */
  const testScenarios = {
    window: {
      centerbottomcenterbottom: {
        at: 'center bottom',
        my: 'center bottom',
        x: 38.5,
        y: 77,
      },
      centerbottomcentercenter: {
        at: 'center center',
        my: 'center bottom',
        x: 38.5,
        y: 77,
      },
      centerbottomcentertop: {
        at: 'center top',
        my: 'center bottom',
        x: 38.5,
        y: -76.984375,
      },
      centerbottomleftbottom: {
        at: 'left bottom',
        my: 'center bottom',
        x: -38.5,
        y: 77,
      },
      centerbottomleftcenter: {
        at: 'left center',
        my: 'center bottom',
        x: -38.5,
        y: 77,
      },
      centerbottomlefttop: {
        at: 'left top',
        my: 'center bottom',
        x: -38.5,
        y: -76.984375,
      },
      centerbottomrightbottom: {
        at: 'right bottom',
        my: 'center bottom',
        x: 38.5,
        y: 77,
      },
      centerbottomrightcenter: {
        at: 'right center',
        my: 'center bottom',
        x: 38.5,
        y: 77,
      },
      centerbottomrightminus80bottomminus40: {
        at: 'right-80 bottom-40',
        my: 'center bottom',
        x: 118.5,
        y: 117,
      },
      centerbottomrighttop: {
        at: 'right top',
        my: 'center bottom',
        x: 38.5,
        y: -76.984375,
      },
      centerminus40topplus40leftplus20ptop: {
        at: 'left+20 top',
        my: 'center-40 top+40',
        x: -58.5,
        y: 40,
      },
      centerplus10perpbottomcenterminus10pertop: {
        at: 'center+110 top',
        my: 'center+150 bottom',
        x: -221.5,
        y: -76.984375,
      },
      centerplus20ptopplus20pcenterbottom: {
        at: 'center bottom',
        my: 'center+100 top-200',
        x: -61.5,
        y: 200,
      },
      centerplus40topminus15pcentercenterplus40: {
        at: 'center center+40',
        my: 'center+40 top+15',
        x: -1.5,
        y: -55,
      },
      centerplus80bottomminus90leftbottom: {
        at: 'left bottom',
        my: 'center+80 bottom-90',
        x: 41.5,
        y: 167,
      },
      centertopcenterbottom: {
        at: 'center bottom',
        my: 'center top',
        x: 38.5,
        y: 0,
      },
      centertopcentercenter: {
        at: 'center center',
        my: 'center top',
        x: 38.5,
        y: 0,
      },
      centertopcenterplus20ptopplus20p: {
        at: 'center+70 top+60',
        my: 'center top',
        x: -31.5,
        y: 60,
      },
      centertopcentertop: { at: 'center top', my: 'center top', x: 38.5, y: 0 },
      centertopleftbottom: {
        at: 'left bottom',
        my: 'center top',
        x: -38.5,
        y: 0,
      },
      centertopleftcenter: {
        at: 'left center',
        my: 'center top',
        x: -38.5,
        y: 0,
      },
      centertoplefttop: { at: 'left top', my: 'center top', x: -38.5, y: 0 },
      centertoprightbottom: {
        at: 'right bottom',
        my: 'center top',
        x: 38.5,
        y: 0,
      },
      centertoprightcenter: {
        at: 'right center',
        my: 'center top',
        x: 38.5,
        y: 0,
      },
      centertoprighttop: { at: 'right top', my: 'center top', x: 38.5, y: 0 },
      leftbottomcenterbottom: {
        at: 'center bottom',
        my: 'left bottom',
        x: 0,
        y: 77,
      },
      leftbottomcentercenter: {
        at: 'center center',
        my: 'left bottom',
        x: 0,
        y: 77,
      },
      leftbottomcentertop: {
        at: 'center top',
        my: 'left bottom',
        x: 0,
        y: -76.984375,
      },
      leftbottomleftbottom: { at: 'left bottom', my: 'left bottom', x: 0, y: 77 },
      leftbottomleftcenter: { at: 'left center', my: 'left bottom', x: 0, y: 77 },
      leftbottomlefttop: {
        at: 'left top',
        my: 'left bottom',
        x: 0,
        y: -76.984375,
      },
      leftbottomrightbottom: {
        at: 'right bottom',
        my: 'left bottom',
        x: 0,
        y: 77,
      },
      leftbottomrightcenter: {
        at: 'right center',
        my: 'left bottom',
        x: 0,
        y: 77,
      },
      leftbottomrighttop: {
        at: 'right top',
        my: 'left bottom',
        x: 0,
        y: -76.984375,
      },
      leftcentercenterbottom: {
        at: 'center bottom',
        my: 'left center',
        x: 0,
        y: 38.5,
      },
      leftcentercentercenter: {
        at: 'center center',
        my: 'left center',
        x: 0,
        y: 38.5,
      },
      leftcentercentertop: {
        at: 'center top',
        my: 'left center',
        x: 0,
        y: -38.484375,
      },
      leftcenterleftbottom: {
        at: 'left bottom',
        my: 'left center',
        x: 0,
        y: 38.5,
      },
      leftcenterleftcenter: {
        at: 'left center',
        my: 'left center',
        x: 0,
        y: 38.5,
      },
      leftcenterlefttop: {
        at: 'left top',
        my: 'left center',
        x: 0,
        y: -38.484375,
      },
      leftcenterrightbottom: {
        at: 'right bottom',
        my: 'left center',
        x: 0,
        y: 38.5,
      },
      leftcenterrightcenter: {
        at: 'right center',
        my: 'left center',
        x: 0,
        y: 38.5,
      },
      leftcenterrighttop: {
        at: 'right top',
        my: 'left center',
        x: 0,
        y: -38.484375,
      },
      lefttopcenterbottom: { at: 'center bottom', my: 'left top', x: 0, y: 0 },
      lefttopcentercenter: { at: 'center center', my: 'left top', x: 0, y: 0 },
      lefttopcentertop: { at: 'center top', my: 'left top', x: 0, y: 0 },
      lefttopleftbottom: { at: 'left bottom', my: 'left top', x: 0, y: 0 },
      lefttopleftcenter: { at: 'left center', my: 'left top', x: 0, y: 0 },
      lefttoplefttop: { at: 'left top', my: 'left top', x: 0, y: 0 },
      lefttoprightbottom: { at: 'right bottom', my: 'left top', x: 0, y: 0 },
      lefttoprightcenter: { at: 'right center', my: 'left top', x: 0, y: 0 },
      lefttoprighttop: { at: 'right top', my: 'left top', x: 0, y: 0 },
      rightbottomcenterbottom: {
        at: 'center bottom',
        my: 'right bottom',
        x: 77,
        y: 77,
      },
      rightbottomcentercenter: {
        at: 'center center',
        my: 'right bottom',
        x: 77,
        y: 77,
      },
      rightbottomcentertop: {
        at: 'center top',
        my: 'right bottom',
        x: 77,
        y: -76.984375,
      },
      rightbottomleftbottom: {
        at: 'left bottom',
        my: 'right bottom',
        x: -77,
        y: 77,
      },
      rightbottomleftcenter: {
        at: 'left center',
        my: 'right bottom',
        x: -77,
        y: 77,
      },
      rightbottomlefttop: {
        at: 'left top',
        my: 'right bottom',
        x: -77,
        y: -76.984375,
      },
      rightbottomrightbottom: {
        at: 'right bottom',
        my: 'right bottom',
        x: 77,
        y: 77,
      },
      rightbottomrightcenter: {
        at: 'right center',
        my: 'right bottom',
        x: 77,
        y: 77,
      },
      rightbottomrighttop: {
        at: 'right top',
        my: 'right bottom',
        x: 77,
        y: -76.984375,
      },
      rightcentercenterbottom: {
        at: 'center bottom',
        my: 'right center',
        x: 77,
        y: 38.5,
      },
      rightcentercentercenter: {
        at: 'center center',
        my: 'right center',
        x: 77,
        y: 38.5,
      },
      rightcentercentertop: {
        at: 'center top',
        my: 'right center',
        x: 77,
        y: -38.484375,
      },
      rightcenterleftbottom: {
        at: 'left bottom',
        my: 'right center',
        x: -77,
        y: 38.5,
      },
      rightcenterleftcenter: {
        at: 'left center',
        my: 'right center',
        x: -77,
        y: 38.5,
      },
      rightcenterlefttop: {
        at: 'left top',
        my: 'right center',
        x: -77,
        y: -38.484375,
      },
      rightcenterrightbottom: {
        at: 'right bottom',
        my: 'right center',
        x: 77,
        y: 38.5,
      },
      rightcenterrightcenter: {
        at: 'right center',
        my: 'right center',
        x: 77,
        y: 38.5,
      },
      rightcenterrighttop: {
        at: 'right top',
        my: 'right center',
        x: 77,
        y: -38.484375,
      },
      righttopcenterbottom: { at: 'center bottom', my: 'right top', x: 77, y: 0 },
      righttopcentercenter: { at: 'center center', my: 'right top', x: 77, y: 0 },
      righttopcentertop: { at: 'center top', my: 'right top', x: 77, y: 0 },
      righttopleftbottom: { at: 'left bottom', my: 'right top', x: -77, y: 0 },
      righttopleftcenter: { at: 'left center', my: 'right top', x: -77, y: 0 },
      righttoplefttop: { at: 'left top', my: 'right top', x: -77, y: 0 },
      righttoprightbottom: { at: 'right bottom', my: 'right top', x: 77, y: 0 },
      righttoprightcenter: { at: 'right center', my: 'right top', x: 77, y: 0 },
      righttoprighttop: { at: 'right top', my: 'right top', x: 77, y: 0 },
    },
    selector: {
      centerbottomcenterbottom: {
        at: 'center bottom',
        my: 'center bottom',
        x: 62.5,
        y: 125,
      },
      centerbottomcentercenter: {
        at: 'center center',
        my: 'center bottom',
        x: 62.5,
        y: 24,
      },
      centerbottomcentertop: {
        at: 'center top',
        my: 'center bottom',
        x: 62.5,
        y: -77,
      },
      centerbottomleftbottom: {
        at: 'left bottom',
        my: 'center bottom',
        x: -38.5,
        y: 125,
      },
      centerbottomleftcenter: {
        at: 'left center',
        my: 'center bottom',
        x: -38.5,
        y: 24,
      },
      centerbottomlefttop: {
        at: 'left top',
        my: 'center bottom',
        x: -38.5,
        y: -77,
      },
      centerbottomrightbottom: {
        at: 'right bottom',
        my: 'center bottom',
        x: 163.5,
        y: 125,
      },
      centerbottomrightcenter: {
        at: 'right center',
        my: 'center bottom',
        x: 163.5,
        y: 24,
      },
      centerbottomrightplus40bottomminus40: {
        at: 'right+40 bottom-40',
        my: 'center bottom',
        x: 203.5,
        y: 85,
      },
      centerbottomrighttop: {
        at: 'right top',
        my: 'center bottom',
        x: 163.5,
        y: -77,
      },
      centerminus40topplus40leftminus20ptop: {
        at: 'left-20% top',
        my: 'center-40 top+40',
        x: -118.890625,
        y: 40,
      },
      centerplus10perpbottomcenterminus10pertop: {
        at: 'center-20% top',
        my: 'center+20% bottom',
        x: 37.5,
        y: -77,
      },
      centerplus40bottomminus40leftbottom: {
        at: 'left bottom',
        my: 'center+40 bottom-40',
        x: 1.5,
        y: 85,
      },
      centerplus40topminus15pcentercenterplus40: {
        at: 'center center+40',
        my: 'center+40 top-15%',
        x: 102.5,
        y: 129.4375,
      },
      centertopcenterbottom: {
        at: 'center bottom',
        my: 'center top',
        x: 62.5,
        y: 202,
      },
      centertopcentercenter: {
        at: 'center center',
        my: 'center top',
        x: 62.5,
        y: 101,
      },
      centertopcenterplus20ptopplus20p: {
        at: 'center+20% top+20%',
        my: 'center top',
        x: 102.890625,
        y: 40.390625,
      },
      centertopcentertop: { at: 'center top', my: 'center top', x: 62.5, y: 0 },
      centertopleftbottom: {
        at: 'left bottom',
        my: 'center top',
        x: -38.5,
        y: 202,
      },
      centertopleftcenter: {
        at: 'left center',
        my: 'center top',
        x: -38.5,
        y: 101,
      },
      centertoplefttop: { at: 'left top', my: 'center top', x: -38.5, y: 0 },
      centertoprightbottom: {
        at: 'right bottom',
        my: 'center top',
        x: 163.5,
        y: 202,
      },
      centertoprightcenter: {
        at: 'right center',
        my: 'center top',
        x: 163.5,
        y: 101,
      },
      centertoprighttop: { at: 'right top', my: 'center top', x: 163.5, y: 0 },
      leftbottomcenterbottom: {
        at: 'center bottom',
        my: 'left bottom',
        x: 101,
        y: 125,
      },
      leftbottomcentercenter: {
        at: 'center center',
        my: 'left bottom',
        x: 101,
        y: 24,
      },
      leftbottomcentertop: {
        at: 'center top',
        my: 'left bottom',
        x: 101,
        y: -77,
      },
      leftbottomleftbottom: {
        at: 'left bottom',
        my: 'left bottom',
        x: 0,
        y: 125,
      },
      leftbottomleftcenter: { at: 'left center', my: 'left bottom', x: 0, y: 24 },
      leftbottomlefttop: { at: 'left top', my: 'left bottom', x: 0, y: -77 },
      leftbottomrightbottom: {
        at: 'right bottom',
        my: 'left bottom',
        x: 202,
        y: 125,
      },
      leftbottomrightcenter: {
        at: 'right center',
        my: 'left bottom',
        x: 202,
        y: 24,
      },
      leftbottomrighttop: { at: 'right top', my: 'left bottom', x: 202, y: -77 },
      leftcentercenterbottom: {
        at: 'center bottom',
        my: 'left center',
        x: 101,
        y: 163.5,
      },
      leftcentercentercenter: {
        at: 'center center',
        my: 'left center',
        x: 101,
        y: 62.5,
      },
      leftcentercentertop: {
        at: 'center top',
        my: 'left center',
        x: 101,
        y: -38.5,
      },
      leftcenterleftbottom: {
        at: 'left bottom',
        my: 'left center',
        x: 0,
        y: 163.5,
      },
      leftcenterleftcenter: {
        at: 'left center',
        my: 'left center',
        x: 0,
        y: 62.5,
      },
      leftcenterlefttop: { at: 'left top', my: 'left center', x: 0, y: -38.5 },
      leftcenterrightbottom: {
        at: 'right bottom',
        my: 'left center',
        x: 202,
        y: 163.5,
      },
      leftcenterrightcenter: {
        at: 'right center',
        my: 'left center',
        x: 202,
        y: 62.5,
      },
      leftcenterrighttop: {
        at: 'right top',
        my: 'left center',
        x: 202,
        y: -38.5,
      },
      lefttopcenterbottom: {
        at: 'center bottom',
        my: 'left top',
        x: 101,
        y: 202,
      },
      lefttopcentercenter: {
        at: 'center center',
        my: 'left top',
        x: 101,
        y: 101,
      },
      lefttopcentertop: { at: 'center top', my: 'left top', x: 101, y: 0 },
      lefttopleftbottom: { at: 'left bottom', my: 'left top', x: 0, y: 202 },
      lefttopleftcenter: { at: 'left center', my: 'left top', x: 0, y: 101 },
      lefttoplefttop: { at: 'left top', my: 'left top', x: 0, y: 0 },
      lefttoprightbottom: { at: 'right bottom', my: 'left top', x: 202, y: 202 },
      lefttoprightcenter: { at: 'right center', my: 'left top', x: 202, y: 101 },
      lefttoprighttop: { at: 'right top', my: 'left top', x: 202, y: 0 },
      rightbottomcenterbottom: {
        at: 'center bottom',
        my: 'right bottom',
        x: 24,
        y: 125,
      },
      rightbottomcentercenter: {
        at: 'center center',
        my: 'right bottom',
        x: 24,
        y: 24,
      },
      rightbottomcentertop: {
        at: 'center top',
        my: 'right bottom',
        x: 24,
        y: -77,
      },
      rightbottomleftbottom: {
        at: 'left bottom',
        my: 'right bottom',
        x: -77,
        y: 125,
      },
      rightbottomleftcenter: {
        at: 'left center',
        my: 'right bottom',
        x: -77,
        y: 24,
      },
      rightbottomlefttop: { at: 'left top', my: 'right bottom', x: -77, y: -77 },
      rightbottomrightbottom: {
        at: 'right bottom',
        my: 'right bottom',
        x: 125,
        y: 125,
      },
      rightbottomrightcenter: {
        at: 'right center',
        my: 'right bottom',
        x: 125,
        y: 24,
      },
      rightbottomrighttop: {
        at: 'right top',
        my: 'right bottom',
        x: 125,
        y: -77,
      },
      rightcentercenterbottom: {
        at: 'center bottom',
        my: 'right center',
        x: 24,
        y: 163.5,
      },
      rightcentercentercenter: {
        at: 'center center',
        my: 'right center',
        x: 24,
        y: 62.5,
      },
      rightcentercentertop: {
        at: 'center top',
        my: 'right center',
        x: 24,
        y: -38.5,
      },
      rightcenterleftbottom: {
        at: 'left bottom',
        my: 'right center',
        x: -77,
        y: 163.5,
      },
      rightcenterleftcenter: {
        at: 'left center',
        my: 'right center',
        x: -77,
        y: 62.5,
      },
      rightcenterlefttop: {
        at: 'left top',
        my: 'right center',
        x: -77,
        y: -38.5,
      },
      rightcenterrightbottom: {
        at: 'right bottom',
        my: 'right center',
        x: 125,
        y: 163.5,
      },
      rightcenterrightcenter: {
        at: 'right center',
        my: 'right center',
        x: 125,
        y: 62.5,
      },
      rightcenterrighttop: {
        at: 'right top',
        my: 'right center',
        x: 125,
        y: -38.5,
      },
      righttopcenterbottom: {
        at: 'center bottom',
        my: 'right top',
        x: 24,
        y: 202,
      },
      righttopcentercenter: {
        at: 'center center',
        my: 'right top',
        x: 24,
        y: 101,
      },
      righttopcentertop: { at: 'center top', my: 'right top', x: 24, y: 0 },
      righttopleftbottom: { at: 'left bottom', my: 'right top', x: -77, y: 202 },
      righttopleftcenter: { at: 'left center', my: 'right top', x: -77, y: 101 },
      righttoplefttop: { at: 'left top', my: 'right top', x: -77, y: 0 },
      righttoprightbottom: {
        at: 'right bottom',
        my: 'right top',
        x: 125,
        y: 202,
      },
      righttoprightcenter: {
        at: 'right center',
        my: 'right top',
        x: 125,
        y: 101,
      },
      righttoprighttop: { at: 'right top', my: 'right top', x: 125, y: 0 },
    },
  };
  /* cSpell:enable */
  
  // Testing `of:` using jQuery or vanilla JS elements can use the same test
  // scenarios and expected values as those using a selector.
  testScenarios.jQuery = testScenarios.selector;
  testScenarios.element = testScenarios.selector;
  
  module.exports = {
    '@tags': ['core'],
    before(browser) {
      browser.drupalInstall().drupalLoginAsAdmin(() => {
        browser
          .drupalRelativeURL('/admin/modules')
          .setValue('input[type="search"]', 'position Shim Test')
          .waitForElementVisible(
            'input[name="modules[position_shim_test][enable]"]',
            1000,
          )
          .click('input[name="modules[position_shim_test][enable]"]')
          .click('input[type="submit"]');
      });
    },
    after(browser) {
      browser.drupalUninstall();
    },
    beforeEach(browser) {
      if (browser.currentTest.name !== 'test position') {
        browser
          .drupalRelativeURL('/position-shim-test-ported-from-jqueryui')
          .waitForElementVisible('#el1', 1000);
      }
    },
    'test position': (browser) => {
      browser
        .resizeWindow(1200, 600)
        .drupalRelativeURL('/position-shim-test')
        .waitForElementPresent('#position-reference-1', 1000)
        .executeAsync(
          // eslint-disable-next-line func-names, prefer-arrow-callback
          function (testIterations, done) {
            const $ = jQuery;
            const toReturn = {};
  
            /**
             * Confirms a coordinate is acceptably close to the expected value.
             *
             * @param {number} actual
             *  The actual coordinate value.
             * @param {number} expected
             *  The expected coordinate value.
             * @return {boolean}
             *  True if the actual is within 3px of the expected.
             */
            const withinRange = (actual, expected) => {
              return actual <= expected + 3 && actual >= expected - 3;
            };
  
            /**
             * Parses a jQuery UI position config string for `at:` or `my:`.
             *
             * A position config string can contain both alignment and offset
             * configuration. This string is parsed and returned as an object that
             * separates horizontal and vertical alignment and their respective
             * offsets into distinct object properties.
             *
             * This is a copy of the parseOffset function from the jQuery position
             * API.
             *
             * @param {string} offset
             *   Offset configuration in jQuery UI Position format.
             * @param {Element} element
             *   The element being positioned.
             * @return {{horizontal: (*|string), verticalOffset: number, vertical: (*|string), horizontalOffset: number}}
             *   The horizontal and vertical alignment and offset values for the element.
             *
             * @see core/misc/position.es6.js
             */
            const parseOffset = (offset, element) => {
              const regexHorizontal = /left|center|right/;
              const regexVertical = /top|center|bottom/;
              const regexOffset = /[+-]\d+(\.[\d]+)?%?/;
              const regexPosition = /^\w+/;
              const regexPercent = /%$/;
              let positions = offset.split(' ');
              if (positions.length === 1) {
                if (regexHorizontal.test(positions[0])) {
                  positions.push('center');
                } else if (regexVertical.test(positions[0])) {
                  positions = ['center'].concat(positions);
                }
              }
  
              const horizontalOffset = regexOffset.exec(positions[0]);
              const verticalOffset = regexOffset.exec(positions[1]);
              positions = positions.map((pos) => regexPosition.exec(pos)[0]);
  
              return {
                horizontalOffset: horizontalOffset
                  ? parseFloat(horizontalOffset[0]) *
                    (regexPercent.test(horizontalOffset[0])
                      ? element.offsetWidth / 100
                      : 1)
                  : 0,
                verticalOffset: verticalOffset
                  ? parseFloat(verticalOffset[0]) *
                    (regexPercent.test(verticalOffset[0])
                      ? element.offsetWidth / 100
                      : 1)
                  : 0,
                horizontal: positions[0],
                vertical: positions[1],
              };
            };
  
            /**
             * Checks the position of an element.
             *
             * The position values of an element are based on their distance
             * relative to the element they're positioned against.
             *
             * @param {jQuery} tip
             *  The element being positioned.
             * @param {Object} options
             *  The position options.
             * @param {string} attachToType
             *  A string representing the data type used for the value of the `of`
             *  option. This could be 'selector', 'window', 'jQuery', 'element'.
             *
             * @param {string} idKey
             *   The unique id of the element indicating the use case scenario.
             *
             * @return {Promise}
             *   Resolve after the tip position is calculated.
             */
            const checkPosition = (tip, options, attachToType, idKey) =>
              new Promise((resolve) => {
                setTimeout(() => {
                  const box = tip[0].getBoundingClientRect();
                  let { x, y } = box;
                  // If the tip is attaching to the window, X and Y are measured
                  // based on their distance from the closest window boundary.
                  if (attachToType === 'window') {
                    // Parse options.at to get the configured the horizontal and
                    // vertical positioning within the window. This will be used
                    // to get the tip distance relative to the configured position
                    // within the window. This provides a reliable way of
                    // getting position info that doesn't rely on an exact
                    // viewport width.
                    const atOffsets = parseOffset(options.at, tip[0]);
  
                    if (atOffsets.horizontal === 'center') {
                      x = document.documentElement.clientWidth / 2 - x;
                    } else if (atOffsets.horizontal === 'right') {
                      x = document.documentElement.clientWidth - x;
                    }
                    if (atOffsets.vertical === 'center') {
                      y = document.documentElement.clientHeight / 2 - y;
                    } else if (atOffsets.vertical === 'bottom') {
                      y = document.documentElement.clientHeight - y;
                    } else {
                      y += window.pageYOffset;
                    }
                  } else {
                    // Measure the distance of the tip from the reference element.
                    const refRect = document
                      .querySelector('#position-reference-1')
                      .getBoundingClientRect();
                    x -= refRect.x;
                    y -= refRect.y;
                  }
                  if (!withinRange(x, options.x) || !withinRange(y, options.y)) {
                    toReturn[
                      idKey
                    ] = `${idKey} EXPECTED x:${options.x} y:${options.y} ACTUAL x:${x} y:${y}`;
                  } else {
                    toReturn[idKey] = true;
                  }
  
                  resolve();
                }, 25);
              });
  
            const attachScenarios = {
              selector: '#position-reference-1',
              window,
              jQuery: $('#position-reference-1'),
              element: document.querySelector('#position-reference-1'),
            };
  
            // Loop through testScenarios and attachScenarios to get config for a
            // positioned tip.
            (async function iterate() {
              const attachToTypes = Object.keys(attachScenarios);
              for (let i = 0; i < attachToTypes.length; i++) {
                const attachToType = attachToTypes[i];
                const scenarios = Object.keys(testIterations[attachToType]);
                for (let j = 0; j < scenarios.length; j++) {
                  const key = scenarios[j];
                  const options = testIterations[attachToType][key];
                  options.of = attachScenarios[attachToType];
                  options.collision = 'none';
                  const idKey = `${attachToType}${key}`;
  
                  // eslint-disable-next-line no-await-in-loop
                  const tip = await new Promise((resolve) => {
                    const addedTip = $(
                      `<div class="test-tip"  style="position:${
                        attachToType === 'window' ? 'fixed' : 'absolute'
                      }" id="${idKey}">${idKey}</div>`,
                    ).appendTo('main');
                    addedTip.position(options);
                    setTimeout(() => {
                      resolve(addedTip);
                    });
                  });
                  // eslint-disable-next-line no-await-in-loop
                  await checkPosition(tip, options, attachToType, idKey);
                  tip.remove();
                }
              }
              done(toReturn);
            })();
          },
          [testScenarios],
          (result) => {
            let numberOfScenarios = 0;
            Object.keys(testScenarios).forEach((scenario) => {
              numberOfScenarios += Object.keys(testScenarios[scenario]).length;
            });
            const valueKeys = Object.keys(result.value);
            browser.assert.equal(valueKeys.length, numberOfScenarios);
            valueKeys.forEach((item) => {
              browser.assert.equal(
                result.value[item],
                true,
                `expected position: ${item}`,
              );
            });
          },
        );
    },
    // The remaining tests are ported from jQuery UI's QUnit tests.
    'my, at, of': (browser) => {
      browser.execute(
        // eslint-disable-next-line func-names
        function () {
          const $ = jQuery;
          const toReturn = {};
          const $elx = $('#elx');
          $elx.position({
            my: 'left top',
            at: 'left top',
            of: '#parentX',
            collision: 'none',
          });
          toReturn['left top, left top'] = {
            actual: $elx.offset(),
            expected: { top: 40, left: 40 },
          };
          $elx.position({
            my: 'left top',
            at: 'left bottom',
            of: '#parentX',
            collision: 'none',
          });
          toReturn['left top, left bottom'] = {
            actual: $elx.offset(),
            expected: { top: 60, left: 40 },
          };
          $elx.position({
            my: 'left',
            at: 'bottom',
            of: '#parentX',
            collision: 'none',
          });
          toReturn['left, bottom'] = {
            actual: $elx.offset(),
            expected: { top: 55, left: 50 },
          };
          $elx.position({
            my: 'left foo',
            at: 'bar baz',
            of: '#parentX',
            collision: 'none',
          });
          toReturn['left foo, bar baz'] = {
            actual: $elx.offset(),
            expected: { top: 45, left: 50 },
          };
          return toReturn;
        },
        [],
        (result) => {
          browser.assert.equal(Object.keys(result.value).length, 4);
          Object.entries(result.value).forEach(([key, value]) => {
            browser.assert.equal(typeof value, 'object');
            browser.assert.deepEqual(value.actual, value.expected, key);
          });
        },
      );
    },
    'multiple elements': (browser) => {
      browser.execute(
        // eslint-disable-next-line func-names
        function () {
          const $ = jQuery;
          const toReturn = {};
          const elements = $('#el1, #el2');
          const result = elements.position({
            my: 'left top',
            at: 'left bottom',
            of: '#parent',
            collision: 'none',
          });
          toReturn['elements return'] = {
            actual: result,
            expected: elements,
          };
          // eslint-disable-next-line func-names
          elements.each(function (index) {
            toReturn[`element${index}`] = {
              actual: $(this).offset(),
              expected: { top: 10, left: 4 },
            };
          });
          return toReturn;
        },
        [],
        (result) => {
          browser.assert.equal(Object.keys(result.value).length, 3);
          Object.entries(result.value).forEach(([key, value]) => {
            browser.assert.equal(typeof value, 'object');
            browser.assert.deepEqual(value.actual, value.expected, key);
          });
        },
      );
    },
    positions: (browser) => {
      browser.execute(
        // eslint-disable-next-line func-names
        function () {
          const $ = jQuery;
          const toReturn = {};
  
          const offsets = {
            left: 0,
            center: 3,
            right: 6,
            top: 0,
            bottom: 6,
          };
          const start = { left: 4, top: 4 };
          const el = $('#el1');
  
          $.each([0, 1], (my) => {
            $.each(['top', 'center', 'bottom'], (vIndex, vertical) => {
              // eslint-disable-next-line max-nested-callbacks
              $.each(['left', 'center', 'right'], (hIndex, horizontal) => {
                const _my = my ? `${horizontal} ${vertical}` : 'left top';
                const _at = !my ? `${horizontal} ${vertical}` : 'left top';
                el.position({
                  my: _my,
                  at: _at,
                  of: '#parent',
                  collision: 'none',
                });
                toReturn[`my: ${_my} at: ${_at}`] = {
                  actual: el.offset(),
                  expected: {
                    top: start.top + offsets[vertical] * (my ? -1 : 1),
                    left: start.left + offsets[horizontal] * (my ? -1 : 1),
                  },
                };
              });
            });
          });
  
          return toReturn;
        },
        [],
        (result) => {
          browser.assert.equal(Object.keys(result.value).length, 17);
          Object.entries(result.value).forEach(([key, value]) => {
            browser.assert.equal(typeof value, 'object');
            browser.assert.deepEqual(value.actual, value.expected, key);
          });
        },
      );
    },
    of: (browser) => {
      browser.execute(
        // eslint-disable-next-line func-names
        function () {
          const $ = jQuery;
          const toReturn = {};
          const $elx = $('#elx');
          const $parentX = $('#parentX');
          const win = $(window);
          let event;
  
          // eslint-disable-next-line func-names
          let scrollTopSupport = function () {
            const support = win.scrollTop(1).scrollTop() === 1;
            win.scrollTop(0);
            // eslint-disable-next-line func-names
            scrollTopSupport = function () {
              return support;
            };
            return support;
          };
  
          $elx.position({
            my: 'left top',
            at: 'left top',
            of: '#parentX',
            collision: 'none',
          });
          toReturn.selector = {
            actual: $elx.offset(),
            expected: { top: 40, left: 40 },
          };
  
          $elx.position({
            my: 'left top',
            at: 'left bottom',
            of: $parentX,
            collision: 'none',
          });
          toReturn['jQuery object'] = {
            actual: $elx.offset(),
            expected: { top: 60, left: 40 },
          };
  
          $elx.position({
            my: 'left top',
            at: 'left top',
            of: $parentX[0],
            collision: 'none',
          });
          toReturn['DOM element'] = {
            actual: $elx.offset(),
            expected: { top: 40, left: 40 },
          };
  
          $elx.position({
            my: 'right bottom',
            at: 'right bottom',
            of: document,
            collision: 'none',
          });
          toReturn.document = {
            actual: $elx.offset(),
            expected: {
              top: $(document).height() - 10,
              left: $(document).width() - 10,
            },
          };
  
          $elx.position({
            my: 'right bottom',
            at: 'right bottom',
            of: $(document),
            collision: 'none',
          });
          toReturn['document as jQuery object'] = {
            actual: $elx.offset(),
            expected: {
              top: $(document).height() - 10,
              left: $(document).width() - 10,
            },
          };
  
          win.scrollTop(0);
  
          $elx.position({
            my: 'right bottom',
            at: 'right bottom',
            of: window,
            collision: 'none',
          });
  
          toReturn.window = {
            actual: $elx.offset(),
            expected: {
              top: win.height() - 10,
              left: win.width() - 10,
            },
          };
  
          $elx.position({
            my: 'right bottom',
            at: 'right bottom',
            of: win,
            collision: 'none',
          });
          toReturn['window as jQuery object'] = {
            actual: $elx.offset(),
            expected: {
              top: win.height() - 10,
              left: win.width() - 10,
            },
          };
  
          if (scrollTopSupport()) {
            win.scrollTop(500).scrollLeft(200);
            $elx.position({
              my: 'right bottom',
              at: 'right bottom',
              of: window,
              collision: 'none',
            });
  
            toReturn['window, scrolled'] = {
              actual: $elx.offset(),
              expected: {
                top: win.height() + 500 - 10,
                left: win.width() + 200 - 10,
              },
            };
  
            win.scrollTop(0).scrollLeft(0);
          }
  
          event = $.extend($.Event('someEvent'), { pageX: 200, pageY: 300 });
          $elx.position({
            my: 'left top',
            at: 'left top',
            of: event,
            collision: 'none',
          });
          toReturn['event - left top, left top'] = {
            actual: $elx.offset(),
            expected: {
              top: 300,
              left: 200,
            },
          };
  
          event = $.extend($.Event('someEvent'), { pageX: 400, pageY: 600 });
          $elx.position({
            my: 'left top',
            at: 'right bottom',
            of: event,
            collision: 'none',
          });
          toReturn['event - left top, right bottom'] = {
            actual: $elx.offset(),
            expected: {
              top: 600,
              left: 400,
            },
          };
  
          return toReturn;
        },
        [],
        (result) => {
          browser.assert.equal(Object.keys(result.value).length, 10);
          Object.entries(result.value).forEach(([key, value]) => {
            browser.assert.equal(typeof value, 'object');
            browser.assert.deepEqual(value.actual, value.expected, key);
          });
        },
      );
    },
    offsets: (browser) => {
      browser.execute(
        // eslint-disable-next-line func-names
        function () {
          const $ = jQuery;
          const toReturn = {
            deepEquals: {},
            trues: {},
          };
          const $elx = $('#elx');
          let offset;
  
          $elx.position({
            my: 'left top',
            at: 'left+10 bottom+10',
            of: '#parentX',
            collision: 'none',
          });
          toReturn.deepEquals['offsets in at'] = {
            actual: $elx.offset(),
            expected: { top: 70, left: 50 },
          };
  
          $elx.position({
            my: 'left+10 top-10',
            at: 'left bottom',
            of: '#parentX',
            collision: 'none',
          });
          toReturn.deepEquals['offsets in my'] = {
            actual: $elx.offset(),
            expected: { top: 50, left: 50 },
          };
  
          $elx.position({
            my: 'left top',
            at: 'left+50% bottom-10%',
            of: '#parentX',
            collision: 'none',
          });
          toReturn.deepEquals['percentage offsets in at'] = {
            actual: $elx.offset(),
            expected: { top: 58, left: 50 },
          };
  
          $elx.position({
            my: 'left-30% top+50%',
            at: 'left bottom',
            of: '#parentX',
            collision: 'none',
          });
          toReturn.deepEquals['percentage offsets in my'] = {
            actual: $elx.offset(),
            expected: { top: 65, left: 37 },
          };
  
          $elx.position({
            my: 'left-30.001% top+50.0%',
            at: 'left bottom',
            of: '#parentX',
            collision: 'none',
          });
          offset = $elx.offset();
          toReturn.trues['decimal percentage top offsets in my'] =
            Math.round(offset.top) === 65;
          toReturn.trues['decimal percentage left offsets in my'] =
            Math.round(offset.left) === 37;
  
          $elx.position({
            my: 'left+10.4 top-10.6',
            at: 'left bottom',
            of: '#parentX',
            collision: 'none',
          });
          offset = $elx.offset();
          toReturn.trues['decimal top offsets in my'] =
            Math.round(offset.top) === 49;
          toReturn.trues['decimal left offsets in my'] =
            Math.round(offset.left) === 50;
  
          $elx.position({
            my: 'left+right top-left',
            at: 'left-top bottom-bottom',
            of: '#parentX',
            collision: 'none',
          });
          toReturn.deepEquals['invalid offsets'] = {
            actual: $elx.offset(),
            expected: { top: 60, left: 40 },
          };
  
          return toReturn;
        },
        [],
        (result) => {
          browser.assert.equal(Object.keys(result.value.trues).length, 4);
          browser.assert.equal(Object.keys(result.value.deepEquals).length, 5);
          Object.entries(result.value.deepEquals).forEach(([key, value]) => {
            browser.assert.deepEqual(value.actual, value.expected, key);
          });
          Object.entries(result.value.trues).forEach(([key, value]) => {
            browser.assert.equal(value, true, key);
          });
        },
      );
    },
    using: (browser) => {
      browser.execute(
        // eslint-disable-next-line func-names
        function () {
          const $ = jQuery;
          const toReturn = {};
          let count = 0;
          const elems = $('#el1, #el2');
          const of = $('#parentX');
          const expectedPosition = { top: 60, left: 60 };
          const expectedFeedback = {
            target: {
              element: of,
              width: 20,
              height: 20,
              left: 40,
              top: 40,
            },
            element: {
              width: 6,
              height: 6,
              left: 60,
              top: 60,
            },
            horizontal: 'left',
            vertical: 'top',
            important: 'vertical',
          };
          const originalPosition = elems
            .position({
              my: 'right bottom',
              at: 'right bottom',
              of: '#parentX',
              collision: 'none',
            })
            .offset();
  
          elems.position({
            my: 'left top',
            at: 'center+10 bottom',
            of: '#parentX',
            using(position, feedback) {
              toReturn[`correct context for call #${count}`] = {
                actual: this,
                expected: elems[count],
              };
              toReturn[`correct position for call #${count}`] = {
                actual: position,
                expected: expectedPosition,
              };
              toReturn[`feedback and element match for call #${count}`] = {
                actual: feedback.element.element[0],
                expected: elems[count],
              };
              // assert.deepEqual(feedback.element.element[0], elems[count]);
              delete feedback.element.element;
              toReturn[`expected feedback after delete for call #${count}`] = {
                actual: feedback,
                expected: expectedFeedback,
              };
              count += 1;
            },
          });
  
          // eslint-disable-next-line func-names
          elems.each(function (index) {
            toReturn[`elements not moved: ${index}`] = {
              actual: $(this).offset(),
              expected: originalPosition,
            };
          });
          return toReturn;
        },
        [],
        (result) => {
          browser.assert.equal(Object.keys(result.value).length, 10);
          Object.entries(result.value).forEach(([key, value]) => {
            browser.assert.equal(typeof value, 'object');
            browser.assert.deepEqual(value.actual, value.expected, key);
          });
        },
      );
    },
    'collision: fit, no collision': (browser) => {
      browser.execute(
        // eslint-disable-next-line func-names
        function () {
          const $ = jQuery;
          const toReturn = {};
          const $elx = $('#elx');
  
          $elx.position({
            my: 'left top',
            at: 'right bottom',
            of: '#parent',
            collision: 'fit',
          });
  
          toReturn['no offset'] = {
            actual: $elx.offset(),
            expected: {
              top: 10,
              left: 10,
            },
          };
  
          $elx.position({
            my: 'left top',
            at: 'right+2 bottom+3',
            of: '#parent',
            collision: 'fit',
          });
  
          toReturn['with offset'] = {
            actual: $elx.offset(),
            expected: {
              top: 13,
              left: 12,
            },
          };
  
          return toReturn;
        },
        [],
        (result) => {
          browser.assert.equal(Object.keys(result.value).length, 2);
          Object.entries(result.value).forEach(([key, value]) => {
            browser.assert.equal(typeof value, 'object');
            browser.assert.deepEqual(value.actual, value.expected, key);
          });
        },
      );
    },
    'collision: fit, collision': (browser) => {
      browser.execute(
        // eslint-disable-next-line func-names
        function () {
          const $ = jQuery;
          const toReturn = {};
          const $elx = $('#elx');
          const win = $(window);
          // eslint-disable-next-line func-names
          let scrollTopSupport = function () {
            const support = win.scrollTop(1).scrollTop() === 1;
            win.scrollTop(0);
            // eslint-disable-next-line func-names
            scrollTopSupport = function () {
              return support;
            };
            return support;
          };
  
          $elx.position({
            my: 'right bottom',
            at: 'left top',
            of: '#parent',
            collision: 'fit',
          });
  
          toReturn['no offset'] = {
            actual: $elx.offset(),
            expected: {
              top: 0,
              left: 0,
            },
          };
  
          $elx.position({
            my: 'right bottom',
            at: 'left+2 top+3',
            of: '#parent',
            collision: 'fit',
          });
  
          toReturn['with offset'] = {
            actual: $elx.offset(),
            expected: {
              top: 0,
              left: 0,
            },
          };
  
          if (scrollTopSupport()) {
            win.scrollTop(300).scrollLeft(200);
            $elx.position({
              my: 'right bottom',
              at: 'left top',
              of: '#parent',
              collision: 'fit',
            });
            toReturn['window scrolled'] = {
              actual: $elx.offset(),
              expected: {
                top: 300,
                left: 200,
              },
            };
  
            win.scrollTop(0).scrollLeft(0);
          }
  
          return toReturn;
        },
        [],
        (result) => {
          browser.assert.equal(Object.keys(result.value).length, 3);
          Object.entries(result.value).forEach(([key, value]) => {
            browser.assert.deepEqual(value.actual, value.expected, key);
          });
        },
      );
    },
    'collision: flip, no collision': (browser) => {
      browser.execute(
        // eslint-disable-next-line func-names
        function () {
          const $ = jQuery;
          const toReturn = {};
          const $elx = $('#elx');
          $elx.position({
            my: 'left top',
            at: 'right bottom',
            of: '#parent',
            collision: 'flip',
          });
  
          toReturn['no offset'] = {
            actual: $elx.offset(),
            expected: {
              top: 10,
              left: 10,
            },
          };
  
          $elx.position({
            my: 'left top',
            at: 'right+2 bottom+3',
            of: '#parent',
            collision: 'flip',
          });
  
          toReturn['with offset'] = {
            actual: $elx.offset(),
            expected: {
              top: 13,
              left: 12,
            },
          };
  
          return toReturn;
        },
        [],
        (result) => {
          browser.assert.equal(Object.keys(result.value).length, 2);
          Object.entries(result.value).forEach(([key, value]) => {
            browser.assert.equal(typeof value, 'object');
            browser.assert.deepEqual(value.actual, value.expected, key);
          });
        },
      );
    },
    'collision: flip, collision': (browser) => {
      browser.execute(
        // eslint-disable-next-line func-names
        function () {
          const $ = jQuery;
          const toReturn = {};
          const $elx = $('#elx');
          $elx.position({
            my: 'right bottom',
            at: 'left top',
            of: '#parent',
            collision: 'flip',
          });
  
          toReturn['no offset'] = {
            actual: $elx.offset(),
            expected: {
              top: 10,
              left: 10,
            },
          };
  
          $elx.position({
            my: 'right bottom',
            at: 'left+2 top+3',
            of: '#parent',
            collision: 'flip',
          });
  
          toReturn['with offset'] = {
            actual: $elx.offset(),
            expected: {
              top: 7,
              left: 8,
            },
          };
  
          return toReturn;
        },
        [],
        (result) => {
          browser.assert.equal(Object.keys(result.value).length, 2);
          Object.entries(result.value).forEach(([key, value]) => {
            browser.assert.equal(typeof value, 'object');
            browser.assert.deepEqual(value.actual, value.expected, key);
          });
        },
      );
    },
    'collision: flipfit, no collision': (browser) => {
      browser.execute(
        // eslint-disable-next-line func-names
        function () {
          const $ = jQuery;
          const toReturn = {};
          const $elx = $('#elx');
          $elx.position({
            my: 'left top',
            at: 'right bottom',
            of: '#parent',
            collision: 'flipfit',
          });
  
          toReturn['no offset'] = {
            actual: $elx.offset(),
            expected: {
              top: 10,
              left: 10,
            },
          };
  
          $elx.position({
            my: 'left top',
            at: 'right+2 bottom+3',
            of: '#parent',
            collision: 'flipfit',
          });
  
          toReturn['with offset'] = {
            actual: $elx.offset(),
            expected: {
              top: 13,
              left: 12,
            },
          };
  
          return toReturn;
        },
        [],
        (result) => {
          browser.assert.equal(Object.keys(result.value).length, 2);
          Object.entries(result.value).forEach(([key, value]) => {
            browser.assert.equal(typeof value, 'object');
            browser.assert.deepEqual(value.actual, value.expected, key);
          });
        },
      );
    },
    'collision: flipfit, collision': (browser) => {
      browser.execute(
        // eslint-disable-next-line func-names
        function () {
          const $ = jQuery;
          const toReturn = {};
          const $elx = $('#elx');
          $elx.position({
            my: 'right bottom',
            at: 'left top',
            of: '#parent',
            collision: 'flipfit',
          });
  
          toReturn['no offset'] = {
            actual: $elx.offset(),
            expected: {
              top: 10,
              left: 10,
            },
          };
  
          $elx.position({
            my: 'right bottom',
            at: 'left+2 top+3',
            of: '#parent',
            collision: 'flipfit',
          });
  
          toReturn['with offset'] = {
            actual: $elx.offset(),
            expected: {
              top: 7,
              left: 8,
            },
          };
  
          return toReturn;
        },
        [],
        (result) => {
          browser.assert.equal(Object.keys(result.value).length, 2);
          Object.entries(result.value).forEach(([key, value]) => {
            browser.assert.equal(typeof value, 'object');
            browser.assert.deepEqual(value.actual, value.expected, key);
          });
        },
      );
    },
    'collision: none, no collision': (browser) => {
      browser.execute(
        // eslint-disable-next-line func-names
        function () {
          const $ = jQuery;
          const toReturn = {};
          const $elx = $('#elx');
          $elx.position({
            my: 'left top',
            at: 'right bottom',
            of: '#parent',
            collision: 'none',
          });
  
          toReturn['no offset'] = {
            actual: $elx.offset(),
            expected: {
              top: 10,
              left: 10,
            },
          };
  
          $elx.position({
            my: 'left top',
            at: 'right+2 bottom+3',
            of: '#parent',
            collision: 'none',
          });
  
          toReturn['with offset'] = {
            actual: $elx.offset(),
            expected: {
              top: 13,
              left: 12,
            },
          };
  
          return toReturn;
        },
        [],
        (result) => {
          browser.assert.equal(Object.keys(result.value).length, 2);
          Object.entries(result.value).forEach(([key, value]) => {
            browser.assert.equal(typeof value, 'object');
            browser.assert.deepEqual(value.actual, value.expected, key);
          });
        },
      );
    },
    'collision: none, collision': (browser) => {
      browser.execute(
        // eslint-disable-next-line func-names
        function () {
          const $ = jQuery;
          const toReturn = {};
          const $elx = $('#elx');
          $elx.position({
            my: 'right bottom',
            at: 'left top',
            of: '#parent',
            collision: 'none',
          });
  
          toReturn['no offset'] = {
            actual: $elx.offset(),
            expected: {
              top: -6,
              left: -6,
            },
          };
  
          $elx.position({
            my: 'right bottom',
            at: 'left+2 top+3',
            of: '#parent',
            collision: 'none',
          });
  
          toReturn['with offset'] = {
            actual: $elx.offset(),
            expected: {
              top: -3,
              left: -4,
            },
          };
  
          return toReturn;
        },
        [],
        (result) => {
          browser.assert.equal(Object.keys(result.value).length, 2);
          Object.entries(result.value).forEach(([key, value]) => {
            browser.assert.equal(typeof value, 'object');
            browser.assert.deepEqual(value.actual, value.expected, key);
          });
        },
      );
    },
    'collision: fit, with margin': (browser) => {
      browser.execute(
        // eslint-disable-next-line func-names
        function () {
          const $ = jQuery;
          const toReturn = {};
          const $elx = $('#elx').css({
            marginTop: 6,
            marginLeft: 4,
          });
          $elx.position({
            my: 'left top',
            at: 'right bottom',
            of: '#parent',
            collision: 'fit',
          });
  
          toReturn['right bottom'] = {
            actual: $elx.offset(),
            expected: {
              top: 10,
              left: 10,
            },
          };
  
          $elx.position({
            my: 'right bottom',
            at: 'left top',
            of: '#parent',
            collision: 'fit',
          });
  
          toReturn['left top'] = {
            actual: $elx.offset(),
            expected: {
              top: 6,
              left: 4,
            },
          };
  
          return toReturn;
        },
        [],
        (result) => {
          browser.assert.equal(Object.keys(result.value).length, 2);
          Object.entries(result.value).forEach(([key, value]) => {
            browser.assert.equal(typeof value, 'object');
            browser.assert.deepEqual(value.actual, value.expected, key);
          });
        },
      );
    },
    'collision: flip, with margin': (browser) => {
      browser.execute(
        // eslint-disable-next-line func-names
        function () {
          const $ = jQuery;
          const toReturn = {};
          const $elx = $('#elx').css({
            marginTop: 6,
            marginLeft: 4,
          });
          $elx.position({
            my: 'left top',
            at: 'right bottom',
            of: '#parent',
            collision: 'flip',
          });
  
          toReturn['left top'] = {
            actual: $elx.offset(),
            expected: {
              top: 10,
              left: 10,
            },
          };
  
          $elx.position({
            my: 'right bottom',
            at: 'left top',
            of: '#parent',
            collision: 'flip',
          });
  
          toReturn['right bottom'] = {
            actual: $elx.offset(),
            expected: {
              top: 10,
              left: 10,
            },
          };
  
          $elx.position({
            my: 'left top',
            at: 'left top',
            of: '#parent',
            collision: 'flip',
          });
  
          toReturn['left top left top'] = {
            actual: $elx.offset(),
            expected: {
              top: 0,
              left: 4,
            },
          };
  
          return toReturn;
        },
        [],
        (result) => {
          browser.assert.equal(Object.keys(result.value).length, 3);
          Object.entries(result.value).forEach(([key, value]) => {
            browser.assert.equal(typeof value, 'object');
            browser.assert.deepEqual(value.actual, value.expected, key);
          });
        },
      );
    },
    within: (browser) => {
      browser.execute(
        // eslint-disable-next-line func-names
        function () {
          const $ = jQuery;
          const toReturn = {};
          const $elx = $('#elx');
          $elx.position({
            my: 'left top',
            at: 'right bottom',
            of: '#parent',
            within: document,
          });
  
          toReturn['within document'] = {
            actual: $elx.offset(),
            expected: {
              top: 10,
              left: 10,
            },
          };
  
          $elx.position({
            my: 'left top',
            at: 'right bottom',
            of: '#parent',
            collision: 'fit',
  
            within: '#within',
          });
  
          toReturn['fit - right bottom'] = {
            actual: $elx.offset(),
            expected: {
              top: 4,
              left: 2,
            },
          };
  
          $elx.position({
            my: 'right bottom',
            at: 'left top',
            of: '#parent',
            within: '#within',
            collision: 'fit',
          });
  
          toReturn['fit - left top'] = {
            actual: $elx.offset(),
            expected: {
              top: 2,
              left: 0,
            },
          };
  
          $elx.position({
            my: 'left top',
            at: 'right bottom',
            of: '#parent',
            within: '#within',
            collision: 'flip',
          });
  
          toReturn['flip - right bottom'] = {
            actual: $elx.offset(),
            expected: {
              top: 10,
              left: -6,
            },
          };
  
          $elx.position({
            my: 'right bottom',
            at: 'left top',
            of: '#parent',
            within: '#within',
            collision: 'flip',
          });
  
          toReturn['flip - left top'] = {
            actual: $elx.offset(),
            expected: {
              top: 10,
              left: -6,
            },
          };
  
          $elx.position({
            my: 'left top',
            at: 'right bottom',
            of: '#parent',
            within: '#within',
            collision: 'flipfit',
          });
  
          toReturn['flipfit - right bottom'] = {
            actual: $elx.offset(),
            expected: {
              top: 4,
              left: 0,
            },
          };
  
          $elx.position({
            my: 'right bottom',
            at: 'left top',
            of: '#parent',
            within: '#within',
            collision: 'flipfit',
          });
  
          toReturn['flipfit - left top'] = {
            actual: $elx.offset(),
            expected: {
              top: 4,
              left: 0,
            },
          };
          return toReturn;
        },
        [],
        (result) => {
          browser.assert.equal(Object.keys(result.value).length, 7);
          Object.entries(result.value).forEach(([key, value]) => {
            browser.assert.equal(typeof value, 'object');
            browser.assert.deepEqual(value.actual, value.expected, key);
          });
        },
      );
    },
    'with scrollbars': (browser) => {
      browser.execute(
        // eslint-disable-next-line func-names
        function () {
          const $ = jQuery;
          const toReturn = {};
  
          const $scrollX = $('#scrollX');
          $scrollX.css({
            width: 100,
            height: 100,
            left: 0,
            top: 0,
          });
  
          const $elx = $('#elx').position({
            my: 'left top',
            at: 'right bottom',
            of: '#scrollX',
            within: '#scrollX',
            collision: 'fit',
          });
  
          toReturn.visible = {
            actual: $elx.offset(),
            expected: {
              top: 90,
              left: 90,
            },
          };
  
          const scrollbarInfo = $.position.getScrollInfo(
            $.position.getWithinInfo($('#scrollX')),
          );
  
          $elx.position({
            of: '#scrollX',
            collision: 'fit',
            within: '#scrollX',
            my: 'left top',
            at: 'right bottom',
          });
  
          toReturn.scroll = {
            actual: $elx.offset(),
            expected: {
              top: 90 - scrollbarInfo.height,
              left: 90 - scrollbarInfo.width,
            },
          };
  
          $scrollX.css({
            overflow: 'auto',
          });
  
          toReturn['auto, no scroll"'] = {
            actual: $elx.offset(),
            expected: {
              top: 90,
              left: 90,
            },
          };
  
          $scrollX
            .css({
              overflow: 'auto',
            })
            .append($('<div>').height(300).width(300));
  
          $elx.position({
            of: '#scrollX',
            collision: 'fit',
            within: '#scrollX',
            my: 'left top',
            at: 'right bottom',
          });
  
          toReturn['auto, with scroll'] = {
            actual: $elx.offset(),
            expected: {
              top: 90 - scrollbarInfo.height,
              left: 90 - scrollbarInfo.width,
            },
          };
  
          return toReturn;
        },
        [],
        (result) => {
          browser.assert.equal(Object.keys(result.value).length, 4);
          Object.entries(result.value).forEach((key, value) => {
            browser.assert.deepEqual(value.actual, value.expected, key);
          });
        },
      );
    },
    fractions: (browser) => {
      browser.execute(
        // eslint-disable-next-line func-names
        function () {
          const $ = jQuery;
          const toReturn = {};
          const $fractionElement = $('#fractions-element').position({
            my: 'left top',
            at: 'left top',
            of: '#fractions-parent',
            collision: 'none',
          });
          toReturn['left top, left top'] = {
            actual: $fractionElement.offset(),
            expected: $('#fractions-parent').offset(),
          };
          return toReturn;
        },
        [],
        (result) => {
          browser.assert.equal(Object.keys(result.value).length, 1);
          Object.entries(result.value).forEach((key, value) => {
            browser.assert.deepEqual(value.actual, value.expected, key);
          });
        },
      );
    },
    'bug #5280: consistent results (avoid fractional values)': (browser) => {
      browser.execute(
        // eslint-disable-next-line func-names
        function () {
          const $ = jQuery;
          const toReturn = {};
          const wrapper = $('#bug-5280');
          const elem = wrapper.children();
          const offset1 = elem
            .position({
              my: 'center',
              at: 'center',
              of: wrapper,
              collision: 'none',
            })
            .offset();
          const offset2 = elem
            .position({
              my: 'center',
              at: 'center',
              of: wrapper,
              collision: 'none',
            })
            .offset();
          toReturn['offsets consistent'] = {
            actual: offset1,
            expected: offset2,
          };
          return toReturn;
        },
        [],
        (result) => {
          browser.assert.equal(Object.keys(result.value).length, 1);
          Object.entries(result.value).forEach((key, value) => {
            browser.assert.deepEqual(value.actual, value.expected, key);
          });
        },
      );
    },
    'bug #8710: flip if flipped position fits more': (browser) => {
      browser.execute(
        // eslint-disable-next-line func-names
        function () {
          const $ = jQuery;
          const toReturn = {};
          const $elx = $('#elx');
          $elx.position({
            my: 'left top',
            within: '#bug-8710-within-smaller',
            of: '#parentX',
            collision: 'flip',
            at: 'right bottom+30',
          });
  
          toReturn['flip - top fits all'] = {
            actual: $elx.offset(),
            expected: {
              top: 0,
              left: 60,
            },
          };
  
          $elx.position({
            my: 'left top',
            within: '#bug-8710-within-smaller',
            of: '#parentX',
            collision: 'flip',
            at: 'right bottom+32',
          });
          toReturn['flip - top fits more'] = {
            actual: $elx.offset(),
            expected: {
              top: -2,
              left: 60,
            },
          };
  
          $elx.position({
            my: 'left top',
            within: '#bug-8710-within-bigger',
            of: '#parentX',
            collision: 'flip',
            at: 'right bottom+32',
          });
          toReturn['no flip - top fits less'] = {
            actual: $elx.offset(),
            expected: {
              top: 92,
              left: 60,
            },
          };
  
          return toReturn;
        },
        [],
        (result) => {
          browser.assert.equal(Object.keys(result.value).length, 3);
          Object.entries(result.value).forEach((key, value) => {
            browser.assert.deepEqual(value.actual, value.expected, key);
          });
        },
      );
    },
  };
  