text: /**
   * @license
   * Copyright (C) 2020 The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   * http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  import '../../../test/common-test-setup-karma.js';
  import './gr-endpoint-decorator.js';
  import '../gr-endpoint-param/gr-endpoint-param.js';
  import '../gr-endpoint-slot/gr-endpoint-slot.js';
  import {html} from '@polymer/polymer/lib/utils/html-tag.js';
  import {resetPlugins} from '../../../test/test-utils.js';
  import {getPluginLoader} from '../../shared/gr-js-api-interface/gr-plugin-loader.js';
  import {getPluginEndpoints} from '../../shared/gr-js-api-interface/gr-plugin-endpoints.js';
  import {_testOnly_initGerritPluginApi} from '../../shared/gr-js-api-interface/gr-gerrit.js';
  
  const pluginApi = _testOnly_initGerritPluginApi();
  
  const basicFixture = fixtureFromTemplate(
      html`<div>
    <gr-endpoint-decorator name="first">
      <gr-endpoint-param name="someparam" value="barbar"></gr-endpoint-param>
      <p>
        <span>test slot</span>
        <gr-endpoint-slot name="test"></gr-endpoint-slot>
      </p>
    </gr-endpoint-decorator>
    <gr-endpoint-decorator name="second">
      <gr-endpoint-param name="someparam" value="foofoo"></gr-endpoint-param>
    </gr-endpoint-decorator>
    <gr-endpoint-decorator name="banana">
      <gr-endpoint-param name="someParam" value="yes"></gr-endpoint-param>
    </gr-endpoint-decorator>
  </div>`
  );
  
  suite('gr-endpoint-decorator', () => {
    let container;
  
    let plugin;
    let decorationHook;
    let decorationHookWithSlot;
    let replacementHook;
  
    setup(done => {
      resetPlugins();
      container = basicFixture.instantiate();
      sinon.stub(getPluginEndpoints(), 'importUrl')
          .callsFake( url => Promise.resolve());
      pluginApi.install(p => plugin = p, '0.1',
          'http://some/plugin/url.html');
      // Decoration
      decorationHook = plugin.registerCustomComponent('first', 'some-module');
      decorationHookWithSlot = plugin.registerCustomComponent(
          'first',
          'some-module-2',
          {slot: 'test'}
      );
      // Replacement
      replacementHook = plugin.registerCustomComponent(
          'second', 'other-module', {replace: true});
      // Mimic all plugins loaded.
      getPluginLoader().loadPlugins([]);
      flush(done);
    });
  
    teardown(() => {
      resetPlugins();
    });
  
    test('imports plugin-provided modules into endpoints', () => {
      const endpoints =
          Array.from(container.querySelectorAll('gr-endpoint-decorator'));
      assert.equal(endpoints.length, 3);
      assert.isTrue(getPluginEndpoints().importUrl.calledWith(
          new URL('http://some/plugin/url.html')
      ));
    });
  
    test('decoration', () => {
      const element =
          container.querySelector('gr-endpoint-decorator[name="first"]');
      const modules = Array.from(element.root.children).filter(
          element => element.nodeName === 'SOME-MODULE');
      assert.equal(modules.length, 1);
      const [module] = modules;
      assert.isOk(module);
      assert.equal(module['someparam'], 'barbar');
      return decorationHook.getLastAttached()
          .then(element => {
            assert.strictEqual(element, module);
          })
          .then(() => {
            element.remove();
            assert.equal(decorationHook.getAllAttached().length, 0);
          });
    });
  
    test('decoration with slot', () => {
      const element =
          container.querySelector('gr-endpoint-decorator[name="first"]');
      const modules = [...element.querySelectorAll('some-module-2')];
      assert.equal(modules.length, 1);
      const [module] = modules;
      assert.isOk(module);
      assert.equal(module['someparam'], 'barbar');
      return decorationHookWithSlot.getLastAttached()
          .then(element => {
            assert.strictEqual(element, module);
          })
          .then(() => {
            element.remove();
            assert.equal(decorationHookWithSlot.getAllAttached().length, 0);
          });
    });
  
    test('replacement', () => {
      const element =
          container.querySelector('gr-endpoint-decorator[name="second"]');
      const module = Array.from(element.root.children).find(
          element => element.nodeName === 'OTHER-MODULE');
      assert.isOk(module);
      assert.equal(module['someparam'], 'foofoo');
      return replacementHook.getLastAttached()
          .then(element => {
            assert.strictEqual(element, module);
          })
          .then(() => {
            element.remove();
            assert.equal(replacementHook.getAllAttached().length, 0);
          });
    });
  
    test('late registration', done => {
      plugin.registerCustomComponent('banana', 'noob-noob');
      flush(() => {
        const element =
            container.querySelector('gr-endpoint-decorator[name="banana"]');
        const module = Array.from(element.root.children).find(
            element => element.nodeName === 'NOOB-NOOB');
        assert.isOk(module);
        done();
      });
    });
  
    test('two modules', done => {
      plugin.registerCustomComponent('banana', 'mod-one');
      plugin.registerCustomComponent('banana', 'mod-two');
      flush(() => {
        const element =
            container.querySelector('gr-endpoint-decorator[name="banana"]');
        const module1 = Array.from(element.root.children).find(
            element => element.nodeName === 'MOD-ONE');
        assert.isOk(module1);
        const module2 = Array.from(element.root.children).find(
            element => element.nodeName === 'MOD-TWO');
        assert.isOk(module2);
        done();
      });
    });
  
    test('late param setup', done => {
      const element =
          container.querySelector('gr-endpoint-decorator[name="banana"]');
      const param = element.querySelector('gr-endpoint-param');
      param['value'] = undefined;
      plugin.registerCustomComponent('banana', 'noob-noob');
      flush(() => {
        let module = Array.from(element.root.children).find(
            element => element.nodeName === 'NOOB-NOOB');
        // Module waits for param to be defined.
        assert.isNotOk(module);
        const value = {abc: 'def'};
        param.value = value;
        flush(() => {
          module = Array.from(element.root.children).find(
              element => element.nodeName === 'NOOB-NOOB');
          assert.isOk(module);
          assert.strictEqual(module['someParam'], value);
          done();
        });
      });
    });
  
    test('param is bound', done => {
      const element =
          container.querySelector('gr-endpoint-decorator[name="banana"]');
      const param = element.querySelector('gr-endpoint-param');
      const value1 = {abc: 'def'};
      const value2 = {def: 'abc'};
      param.value = value1;
      plugin.registerCustomComponent('banana', 'noob-noob');
      flush(() => {
        const module = Array.from(element.root.children).find(
            element => element.nodeName === 'NOOB-NOOB');
        assert.strictEqual(module['someParam'], value1);
        param.value = value2;
        assert.strictEqual(module['someParam'], value2);
        done();
      });
    });
  });
  