/* eslint-disable max-len */
import { fixture, assert, html, nextFrame, aTimeout } from '@open-wc/testing'
import sinon from 'sinon'
import { AmfDefinitions, ApiDefinitions, IRequestAuthorization } from '@api-client/core/browser.js'
import * as InputCache from '../../../src/amf/lib/InputCache.js'
import { AmfLoader } from '../AmfLoader.js'
import { loadMonaco } from '../MonacoSetup.js'
import { EventTypes } from '../../../src/events/amf/EventTypes.js'
import { DomEventsAmfStore } from '../../../src/index.js'
import ApiRequestEditorElement from '../../../src/elements/amf/ApiRequestEditor.element.js'
import { SecuritySelectorListItem } from '../../../src/amf/types.js'
import '../../../src/define/amf/api-request-editor.js'

describe.skip('ApiRequestEditorElement', () => {
  const store = new DomEventsAmfStore(window)
  store.listen()

  let loader: AmfLoader
  before(async () => {
    await loadMonaco()
    loader = new AmfLoader()
  })

  async function basicFixture(): Promise<ApiRequestEditorElement> {
    const element = await fixture(html`<api-request-editor></api-request-editor>`)
    await aTimeout(2)
    return element as ApiRequestEditorElement
  }

  async function allowCustomFixture(): Promise<ApiRequestEditorElement> {
    const element = await fixture(html`<api-request-editor allowCustom></api-request-editor>`)
    await aTimeout(2)
    return element as ApiRequestEditorElement
  }

  async function modelFixture(selected?: string): Promise<ApiRequestEditorElement> {
    const element = await fixture(html`<api-request-editor .domainId="${selected}"></api-request-editor>`)
    await aTimeout(2)
    return element as ApiRequestEditorElement
  }

  async function urlEditorFixture(selected?: string): Promise<ApiRequestEditorElement> {
    const element = await fixture(html`<api-request-editor .domainId="${selected}" urlEditor></api-request-editor>`)
    await aTimeout(2)
    return element as ApiRequestEditorElement
  }

  async function urlLabelFixture(selected?: string): Promise<ApiRequestEditorElement> {
    const element = await fixture(html`<api-request-editor .domainId="${selected}" urlLabel></api-request-editor>`)
    await aTimeout(2)
    return element as ApiRequestEditorElement
  }

  async function customBaseUriSlotFixture(): Promise<ApiRequestEditorElement> {
    const element = await fixture(
      html` <api-request-editor>
        <ui-list-item slot="custom-base-uri" data-value="http://customServer.com">Custom</ui-list-item>
      </api-request-editor>`
    )
    await aTimeout(2)
    return element as ApiRequestEditorElement
  }

  async function noSelectorFixture(): Promise<ApiRequestEditorElement> {
    const element = await fixture(
      html` <api-request-editor noServerSelector>
        <ui-list-item slot="custom-base-uri" data-value="http://customServer.com">http://customServer.com</ui-list-item>
      </api-request-editor>`
    )
    await aTimeout(2)
    return element as ApiRequestEditorElement
  }

  async function hideOptionalFixture(selected?: string): Promise<ApiRequestEditorElement> {
    const element = await fixture(
      html`<api-request-editor .domainId="${selected}" allowHideOptional></api-request-editor>`
    )
    await aTimeout(2)
    return element as ApiRequestEditorElement
  }

  describe('initialization', () => {
    it('can be initialized with document.createElement', () => {
      const element = document.createElement('api-request-editor')
      assert.ok(element)
    })

    it('does not render the URL editor by default', async () => {
      const element = await basicFixture()
      const node = element.shadowRoot!.querySelector('.url-input')
      assert.notOk(node)
    })

    it('renders the url editor when configured', async () => {
      const element = await urlEditorFixture()
      const node = element.shadowRoot!.querySelector('.url-input')
      assert.ok(node)
    })

    it('renders the send button without the model', async () => {
      const element = await basicFixture()
      const node = element.shadowRoot!.querySelector('.send-button')
      assert.ok(node)
    })

    it('send button has "send" label', async () => {
      const element = await basicFixture()
      const node = element.shadowRoot!.querySelector('.send-button') as HTMLElement
      assert.equal((node.textContent as string).trim(), 'Send')
    })

    it('does not render headers form without the model', async () => {
      const element = await basicFixture()
      const node = element.shadowRoot!.querySelector('.params-section.header')
      assert.notOk(node)
    })

    it('does not render parameters form without the model', async () => {
      const element = await basicFixture()
      const node = element.shadowRoot!.querySelector('.params-section.parameter')
      assert.notOk(node)
    })

    it('does not render payload editor without the model', async () => {
      const element = await basicFixture()
      const node = element.shadowRoot!.querySelector('.body-editor')
      assert.notOk(node)
    })

    it('does not render authorization editor without the model', async () => {
      const element = await basicFixture()
      const node = element.shadowRoot!.querySelector('api-authorization-editor')
      assert.notOk(node)
    })

    it('does not render url label', async () => {
      const element = await basicFixture()
      const node = element.shadowRoot!.querySelector('.url-label')
      assert.notOk(node)
    })
  })

  describe('custom properties', () => {
    let element: ApiRequestEditorElement
    beforeEach(async () => {
      element = await allowCustomFixture()
    })

    it('renders parameters form', async () => {
      const node = element.shadowRoot!.querySelector('.params-section.parameter')
      assert.ok(node)
    })

    it('renders the parameters add button', async () => {
      const node = element.shadowRoot!.querySelector('.params-section.parameter .add-custom-button')
      assert.ok(node)
    })

    it('renders header form', async () => {
      const node = element.shadowRoot!.querySelector('.params-section.header')
      assert.ok(node)
    })

    it('renders the header add button', async () => {
      const node = element.shadowRoot!.querySelector('.params-section.header .add-custom-button')
      assert.ok(node)
    })
  })

  describe('OAuth2 redirect URI change event', () => {
    let element: ApiRequestEditorElement
    beforeEach(async () => {
      element = await basicFixture()
    })

    // it('sets redirectUri from the event (legacy)', () => {
    //   const value = 'https://auth.domain.com'
    //   document.body.dispatchEvent(
    //     new CustomEvent(EventTypes.Request.redirectUriChangeLegacy, {
    //       bubbles: true,
    //       detail: {
    //         value,
    //       },
    //     })
    //   )
    //   assert.equal(element.redirectUri, value)
    // })

    it('sets redirectUri from the event', () => {
      const value = 'https://auth.domain.com'
      document.body.dispatchEvent(
        new CustomEvent(EventTypes.Request.redirectUriChange, {
          bubbles: true,
          detail: {
            value,
          },
        })
      )
      assert.equal(element.redirectUri, value)
    })
  })

  // describe('[responseHandler]()', () => {
  //   let element: ApiRequestEditorElement;
  //   const requestId = 'test-id';
  //   beforeEach(async () => {
  //     InputCache.globalValues.clear();
  //     element = await basicFixture();
  //     element.loadingRequest = true;
  //     element.requestId = requestId;
  //   });

  //   it('does nothing when the id is different', () => {
  //     const e = new ApiResponseEvent(EventTypes.Request.apiResponse, {
  //       id: 'otherId',
  //       isError: true,
  //       loadingTime: 0,
  //       request: {
  //         method: '',
  //         url: '',
  //       },
  //       response: {
  //         status: 0,
  //       },
  //     });
  //     element[responseHandler](e);
  //     assert.isTrue(element.loadingRequest);
  //   });

  //   it('does nothing when no detail', () => {
  //     const e = new CustomEvent(EventTypes.Request.apiResponse);
  //     element[responseHandler](e);
  //     assert.isTrue(element.loadingRequest);
  //   });

  //   it('resets the loadingRequest property', () => {
  //     const e = new CustomEvent(EventTypes.Request.apiResponse, {
  //       detail: {
  //         id: requestId,
  //       }
  //     });
  //     element[responseHandler](e);
  //     assert.isFalse(element.loadingRequest);
  //   });

  //   it('event handler is connected', () => {
  //     RequestEvents.apiResponse(document.body, {
  //       id: requestId,
  //       isError: true,
  //       loadingTime: 0,
  //       request: {
  //         method: '',
  //         url: '',
  //       },
  //       response: {
  //         status: 0,
  //       },
  //     });
  //     assert.isFalse(element.loadingRequest);
  //   });
  // });

  describe('Unit #1', () => {
    const httpbinApi = 'httpbin'
    const driveApi = 'google-drive-api'
    const demoApi = 'demo-api'

    describe('http method computation', () => {
      let model: AmfDefinitions.IAmfDocument
      before(async () => {
        model = await loader.getGraph(httpbinApi)
        store.amf = model
      })

      it('sets httpMethod property (get)', async () => {
        const method = loader.lookupOperation(model, '/anything', 'get') as AmfDefinitions.IAmfOperation
        const element = await modelFixture(method['@id'])
        assert.equal(element.httpMethod, 'get')
      })

      it('sets httpMethod property (post)', async () => {
        const method = loader.lookupOperation(model, '/anything', 'post') as AmfDefinitions.IAmfOperation
        const element = await modelFixture(method['@id'])
        assert.equal(element.httpMethod, 'post')
      })

      it('sets httpMethod property (put)', async () => {
        const method = loader.lookupOperation(model, '/anything', 'put') as AmfDefinitions.IAmfOperation
        const element = await modelFixture(method['@id'])
        assert.equal(element.httpMethod, 'put')
      })

      it('sets httpMethod property (delete)', async () => {
        const method = loader.lookupOperation(model, '/anything', 'delete') as AmfDefinitions.IAmfOperation
        const element = await modelFixture(method['@id'])
        assert.equal(element.httpMethod, 'delete')
      })
    })

    describe('#payloads and #payload', () => {
      let model: AmfDefinitions.IAmfDocument
      before(async () => {
        model = await loader.getGraph(driveApi)
        store.amf = model
      })

      it('sets the #payloads for the endpoint', async () => {
        const method = loader.lookupOperation(model, '/files/{fileId}', 'patch') as AmfDefinitions.IAmfOperation
        const element = await modelFixture(method['@id'])
        assert.typeOf(element.payloads, 'array')
        assert.lengthOf(element.payloads as ApiDefinitions.IApiPayload[], 1)
      })

      it('sets the #payload property', async () => {
        const method = loader.lookupOperation(model, '/files/{fileId}', 'patch') as AmfDefinitions.IAmfOperation
        const element = await modelFixture(method['@id'])
        assert.typeOf(element.payload, 'object')
      })
    })

    describe('Security computations', () => {
      let model: AmfDefinitions.IAmfDocument
      before(async () => {
        model = await loader.getGraph(driveApi)
        store.amf = model
      })

      it('does not set variables when no security', async () => {
        const element = await basicFixture()
        assert.isUndefined(element.security)
      })

      it('sets the security value', async () => {
        const method = loader.lookupOperation(model, '/files', 'get') as AmfDefinitions.IAmfOperation
        const element = await modelFixture(method['@id'])
        assert.typeOf(element.security, 'array', 'has the security')
        assert.lengthOf(element.security as SecuritySelectorListItem[], 1, 'has the single scheme')
        const [scheme] = element.security as SecuritySelectorListItem[]
        assert.deepEqual(scheme.types, ['OAuth 2.0'], 'has types definition')
        assert.deepEqual(scheme.labels, ['oauth_2_0'], 'has labels definition')
        assert.typeOf(scheme.security, 'object', 'has the security definition')
      })

      it('sets the selectedSecurity', async () => {
        const method = loader.lookupOperation(model, '/files', 'get') as AmfDefinitions.IAmfOperation
        const element = await modelFixture(method['@id'])
        assert.isNotEmpty(element.selectedSecurity)
      })
    })

    // describe('RAML parameters computations', () => {
    //   let model: AmfDefinitions.IAmfDocument;
    //   before(async () => {
    //     model = await loader.getGraph(demoApi);
    //     store.amf = model;
    //   });

    //   it('sets server parameters when no operation', async () => {
    //     const element = await basicFixture();
    //     assert.lengthOf(element.parametersValue, 1, 'has a single parameter');
    //     const [param] = element.parametersValue;
    //     assert.equal(param.binding, 'path', 'has a path parameter');
    //     assert.equal(param.source, 'server', 'the parameter was set by the server');
    //   });

    //   it('sets path parameters from the server and the endpoint', async () => {
    //     const method = loader.lookupOperation(model, '/test-parameters/{feature}', 'get')
    //       as AmfDefinitions.IAmfOperation;
    //     const element = await modelFixture(method['@id']);
    //     const path = element.parametersValue.filter(p => p.binding === 'path')
    //     assert.lengthOf(path, 2, 'has all parameters');
    //     assert.typeOf(
    //       path.find(p => p.parameter.name === 'feature'),
    //       'object',
    //       'has the endpoints path parameter'
    //     );
    //     assert.typeOf(
    //       path.find(p => p.parameter.name === 'instance'),
    //       'object',
    //       'has the server path parameter'
    //     );
    //   });

    //   it('sets query parameters', async () => {
    //     const method = loader.lookupOperation(model, '/test-parameters/{feature}', 'get')
    //        as AmfDefinitions.IAmfOperation;
    //     const element = await modelFixture(method['@id']);
    //     const path = element.parametersValue.filter(p => p.binding === 'query')
    //     assert.lengthOf(path, 3, 'has all parameters');
    //     assert.typeOf(
    //       path.find(p => p.parameter.name === 'testRepeatable'),
    //       'object',
    //       'has the testRepeatable parameter'
    //     );
    //     assert.typeOf(
    //       path.find(p => p.parameter.name === 'numericRepeatable'),
    //       'object',
    //       'has the numericRepeatable parameter'
    //     );
    //     assert.typeOf(
    //       path.find(p => p.parameter.name === 'notRequiredRepeatable'),
    //       'object',
    //       'has the notRequiredRepeatable parameter'
    //     );
    //   });

    //   it('sets header parameters', async () => {
    //     const method = loader.lookupOperation(model, '/people', 'get') as AmfDefinitions.IAmfOperation;
    //     const element = await modelFixture(method['@id']);
    //     const params = element.parametersValue.filter(p => p.binding === 'header');
    //     assert.lengthOf(params, 2, 'has all parameters');
    //     assert.typeOf(
    //       params.find(p => p.parameter.name === 'x-people-op-id'),
    //       'object',
    //       'has the x-people-op-id parameter'
    //     );
    //   });
    // });

    describe('#mimeType', () => {
      let model: AmfDefinitions.IAmfDocument
      before(async () => {
        model = await loader.getGraph(demoApi)
        store.amf = model
      })

      it('sets content type from the body', async () => {
        const method = loader.lookupOperation(model, '/content-type', 'post') as AmfDefinitions.IAmfOperation
        const element = await modelFixture(method['@id'])
        assert.equal(element.mimeType, 'application/json')
      })
    })

    describe('ui state', () => {
      let model: AmfDefinitions.IAmfDocument
      before(async () => {
        model = await loader.getGraph(demoApi)
        store.amf = model
      })

      it('renders the authorization editor when authorization is required', async () => {
        const method = loader.lookupOperation(model, '/messages', 'get') as AmfDefinitions.IAmfOperation
        const element = await modelFixture(method['@id'])
        const node = element.shadowRoot!.querySelector('api-authorization-editor')
        assert.ok(node)
      })

      it('renders query/uri forms when model is set', async () => {
        const method = loader.lookupOperation(model, '/people', 'get') as AmfDefinitions.IAmfOperation
        const element = await modelFixture(method['@id'])
        const node = element.shadowRoot!.querySelector('.params-section.parameter')
        assert.ok(node)
      })

      it('renders headers editor when model is set', async () => {
        const method = loader.lookupOperation(model, '/people', 'get') as AmfDefinitions.IAmfOperation
        const element = await modelFixture(method['@id'])
        const node = element.shadowRoot!.querySelector('.params-section.header')
        assert.ok(node)
      })

      it('renders the URL editor when urlEditor', async () => {
        const method = loader.lookupOperation(model, '/people', 'get') as AmfDefinitions.IAmfOperation
        const element = await urlEditorFixture(method['@id'])
        const node = element.shadowRoot!.querySelector('.url-input')
        assert.ok(node)
      })
    })

    describe('execute()', () => {
      let model: AmfDefinitions.IAmfDocument
      before(async () => {
        model = await loader.getGraph(demoApi)
        store.amf = model
      })

      let element: ApiRequestEditorElement
      beforeEach(async () => {
        InputCache.globalValues.clear()
        const method = loader.lookupOperation(model, '/people', 'get') as AmfDefinitions.IAmfOperation
        element = await modelFixture(method['@id'])
      })

      // it('dispatches the legacy request event', () => {
      //   const spy = sinon.spy()
      //   element.addEventListener(EventTypes.Request.apiRequestLegacy, spy)
      //   element.execute()
      //   assert.isTrue(spy.called)
      // })

      // it('dispatches the request event', () => {
      //   const spy = sinon.spy()
      //   element.addEventListener(EventTypes.Request.apiRequest, spy)
      //   element.execute()
      //   assert.isTrue(spy.called)
      // })

      it('sets loadingRequest property', () => {
        element.execute()
        assert.isTrue(element.loadingRequest)
      })

      // it('sets requestId property', () => {
      //   element.execute()
      //   assert.typeOf(element.requestId, 'string')
      // })

      it('calls the serialize() function', () => {
        const spy = sinon.spy(element, 'serialize')
        element.execute()
        assert.isTrue(spy.called)
      })

      // it('the event has the serialized request', () => {
      //   const spy = sinon.spy()
      //   element.addEventListener(EventTypes.Request.apiRequest, spy)
      //   element.execute()
      //   const { detail } = spy.args[0][0]
      //   assert.equal(detail.method, 'GET')
      //   assert.equal(detail.url, 'http://production.domain.com/people')
      //   assert.equal(detail.headers, 'x-people-op-id: 9719fa6f-c666-48e0-a191-290890760b30\nx-rate-client-id: 5757gh76')
      //   assert.typeOf(detail.id, 'string')
      //   assert.typeOf(detail.authorization, 'array', 'has the authorization array')
      //   assert.lengthOf(detail.authorization, 1, 'has as single authorization definition')
      // })
    })

    describe('abort()', () => {
      let model: AmfDefinitions.IAmfDocument
      before(async () => {
        model = await loader.getGraph(demoApi)
        store.amf = model
      })

      let element: ApiRequestEditorElement
      beforeEach(async () => {
        InputCache.globalValues.clear()
        const method = loader.lookupOperation(model, '/people', 'get') as AmfDefinitions.IAmfOperation
        element = await modelFixture(method['@id'])
        element.loadingRequest = true
        // element.requestId = 'test-request'
        element.requestUpdate()
        await element.updateComplete
      })

      // it('dispatched the event when the abort button pressed', () => {
      //   const spy = sinon.spy()
      //   element.addEventListener(EventTypes.Request.abortApiRequest, spy)
      //   const button = element.shadowRoot!.querySelector('.send-button.abort') as HTMLElement
      //   button.click()
      //   assert.isTrue(spy.calledOnce)
      // })

      // it('dispatched the legacy event when the abort button pressed', () => {
      //   const spy = sinon.spy()
      //   element.addEventListener(EventTypes.Request.abortApiRequestLegacy, spy)
      //   const button = element.shadowRoot!.querySelector('.send-button.abort') as HTMLElement
      //   button.click()
      //   assert.isTrue(spy.calledOnce)
      // })

      // it('the event contains the url and the id', () => {
      //   const spy = sinon.spy()
      //   element.addEventListener(EventTypes.Request.abortApiRequest, spy)
      //   element.abort()
      //   const { detail } = spy.args[0][0]
      //   assert.equal(detail.url, element.url, 'URL is set')
      //   assert.equal(detail.id, 'test-request', 'id is set')
      // })

      it('resets the loadingRequest property', () => {
        element.abort()
        assert.isFalse(element.loadingRequest)
      })

      // it('resets the requestId property', () => {
      //   element.abort()
      //   assert.isUndefined(element.requestId)
      // })
    })

    describe('serialize()', () => {
      let model: AmfDefinitions.IAmfDocument
      before(async () => {
        model = await loader.getGraph(demoApi)
        store.amf = model
      })

      beforeEach(async () => {
        InputCache.globalValues.clear()
      })

      it('returns an object', async () => {
        const method = loader.lookupOperation(model, '/people', 'get') as AmfDefinitions.IAmfOperation
        const element = await modelFixture(method['@id'])
        const result = await element.serialize()
        assert.typeOf(result, 'object')
      })

      it('sets editor url', async () => {
        const method = loader.lookupOperation(model, '/people', 'get') as AmfDefinitions.IAmfOperation
        const element = await modelFixture(method['@id'])
        await nextFrame()
        const result = await element.serialize()
        assert.equal(result.expects.url, 'http://production.domain.com/people')
      })

      it('sets editor method', async () => {
        const method = loader.lookupOperation(model, '/people', 'get') as AmfDefinitions.IAmfOperation
        const element = await modelFixture(method['@id'])
        const result = await element.serialize()
        assert.equal(result.expects.method, 'GET')
      })

      it('sets headers from the editor', async () => {
        const method = loader.lookupOperation(model, '/post-headers', 'post') as AmfDefinitions.IAmfOperation
        const element = await modelFixture(method['@id'])
        await aTimeout(10)
        const result = await element.serialize()
        assert.equal(result.expects.headers, 'x-string: my-value\ncontent-type: application/json')
      })

      it('sets editor payload', async () => {
        const method = loader.lookupOperation(model, '/people', 'post') as AmfDefinitions.IAmfOperation
        const element = await modelFixture(method['@id'])
        await aTimeout(0)
        const result = await element.serialize()
        assert.typeOf(result.expects.payload, 'string', 'has the payload')

        const body = JSON.parse(String(result.expects.payload))
        // just any value, it's not important here.
        assert.equal(body.gender, 'female', 'has payload values')
      })

      it('sets authorization data', async () => {
        const method = loader.lookupOperation(model, '/people/{personId}', 'get') as AmfDefinitions.IAmfOperation
        const element = await modelFixture(method['@id'])
        await aTimeout(0)
        const result = await element.serialize()
        assert.typeOf(result.authorization, 'array')
        assert.lengthOf(result.authorization as IRequestAuthorization[], 1)
        assert.equal((result.authorization as IRequestAuthorization[])[0].type, 'custom')
      })

      it('does not set editor payload when GET request', async () => {
        const postMethod = loader.lookupOperation(model, '/people', 'post') as AmfDefinitions.IAmfOperation
        const element = await modelFixture(postMethod['@id'])
        await aTimeout(0)
        const getMethod = loader.lookupOperation(model, '/people', 'get') as AmfDefinitions.IAmfOperation
        element.domainId = getMethod['@id']
        await aTimeout(0)
        const result = await element.serialize()
        assert.isUndefined(result.expects.payload)
      })

      it('does not set editor payload when HEAD request', async () => {
        const postMethod = loader.lookupOperation(model, '/people', 'post') as AmfDefinitions.IAmfOperation
        const element = await modelFixture(postMethod['@id'])
        await aTimeout(0)
        const getMethod = loader.lookupOperation(model, '/people', 'head') as AmfDefinitions.IAmfOperation
        element.domainId = getMethod['@id']
        await aTimeout(0)
        const result = await element.serialize()
        assert.isUndefined(result.expects.payload)
      })

      // it('sets the content-type header if not present but set in component', async () => {
      //   const method = loader.lookupOperation(model, '/people', 'post') as AmfDefinitions.IAmfOperation;
      //   const element = await modelFixture(method['@id']);
      //   element.parametersValue = element.parametersValue.filter(p => p.binding !== 'header');
      //   const result = await element.serialize();
      //   assert.equal(result.headers, 'content-type: application/json');
      // });
    })

    describe('[sendHandler]()', () => {
      let model: AmfDefinitions.IAmfDocument
      before(async () => {
        model = await loader.getGraph(demoApi)
        store.amf = model
      })

      // it('calls authAndExecute() when authorization is required', async () => {
      //   const method = store.lookupOperation(model, '/messages', 'get') as AmfDefinitions.IAmfOperation;
      //   const element = await modelFixture(method['@id']);
      //   await aTimeout(5);
      //   const spy = sinon.spy(element, 'authAndExecute');
      //   const button = element.shadowRoot!.querySelector('.send-button') as HTMLElement;
      //   /** @type HTMLElement */ (button).click();
      //   await aTimeout(25);
      //   assert.isTrue(spy.called);
      // });

      it('calls execute() when authorization is not required', async () => {
        const method = loader.lookupOperation(model, '/people', 'get') as AmfDefinitions.IAmfOperation
        const element = await modelFixture(method['@id'])
        const spy = sinon.spy(element, 'execute')
        const button = element.shadowRoot!.querySelector('.send-button') as HTMLElement
        button.click()
        assert.isTrue(spy.called)
      })
    })

    describe('#urlLabel', () => {
      let model: AmfDefinitions.IAmfDocument
      before(async () => {
        model = await loader.getGraph(demoApi)
        store.amf = model
      })

      it('renders the url label', async () => {
        const method = loader.lookupOperation(model, '/people', 'get') as AmfDefinitions.IAmfOperation
        const element = await urlLabelFixture(method['@id'])
        const node = element.shadowRoot!.querySelector('.url-label')
        assert.ok(node)
      })

      it('renders the url value', async () => {
        const method = loader.lookupOperation(model, '/people', 'get') as AmfDefinitions.IAmfOperation
        const element = await urlLabelFixture(method['@id'])
        await nextFrame()
        const node = element.shadowRoot!.querySelector('.url-label') as HTMLElement
        const text = (node.textContent as string).trim()
        assert.equal(text, element.url)
      })
    })

    // TODO: fixme
    // describe.skip('slotted servers', () => {
    //   let element: ApiRequestEditorElement;
    //   let model: AmfDefinitions.IAmfDocument;
    //   before(async () => {
    //     model = await loader.getGraph();
    //     store.amf = model;
    //   });

    //   beforeEach(async () => {
    //     element = await customBaseUriSlotFixture();
    //     const op = loader.lookupOperation(model, '/people/{personId}', 'get') as AmfDefinitions.IAmfOperation;
    //     element.domainId = op['@id'];
    //     await aTimeout(2);
    //   });

    //   it('should update api-url-editor value after selecting slotted base uri', async () => {
    //     element[serverHandler](new CustomEvent('apiserverchanged', { detail: { value: 'http://customServer.com', type: 'custom' } }));
    //     await aTimeout(2);
    //     assert.equal(element.url, 'http://customServer.com/people/1234');
    //   });

    //   it('changing the URL in the url input changes the parameters', async () => {
    //     element.urlEditor = true;
    //     await nextFrame();
    //     element[serverHandler](new CustomEvent('apiserverchanged', { detail: { value: 'http://customServer.com', type: 'custom' } }));
    //     await aTimeout(2);
    //     const input = (element.shadowRoot!.querySelector('.url-input')) as HTMLInputElement;
    //     input.value = 'http://customServer.com/people/5678';
    //     input.dispatchEvent(new Event('change'));
    //     await nextFrame();
    //     assert.equal(element.url, 'http://customServer.com/people/5678', 'url value is changed');
    //     const paramInput = (element.shadowRoot!.querySelector('[name="personId"]')) as HTMLInputElement;
    //     assert.equal(paramInput.value, '5678', 'the input is changed');
    //   });
    // });

    describe('#allowHideOptional', () => {
      let model: AmfDefinitions.IAmfDocument
      before(async () => {
        model = await loader.getGraph(demoApi)
        store.amf = model
      })

      describe('query parameters', () => {
        it('renders the optional toggle button', async () => {
          const method = loader.lookupOperation(model, '/people', 'get') as AmfDefinitions.IAmfOperation
          const element = await hideOptionalFixture(method['@id'])
          const toggle = element.shadowRoot!.querySelector('.query-params .toggle-optional-switch')
          assert.ok(toggle)
        })

        it('optional parameters are hidden', async () => {
          const method = loader.lookupOperation(model, '/people', 'get') as AmfDefinitions.IAmfOperation
          const element = await hideOptionalFixture(method['@id'])
          const allItems = element.shadowRoot!.querySelectorAll('.query-params .form-item.optional')
          Array.from(allItems).forEach((node) => {
            const { display } = getComputedStyle(node)
            assert.equal(display, 'none')
          })
        })

        it('toggles the visibility of the parameters', async () => {
          const method = loader.lookupOperation(model, '/people', 'get') as AmfDefinitions.IAmfOperation
          const element = await hideOptionalFixture(method['@id'])
          const toggle = element.shadowRoot!.querySelector('.query-params .toggle-optional-switch') as HTMLElement
          toggle.click()
          await nextFrame()
          assert.deepEqual(element.openedOptional, ['query'], 'adds query to the openedOptional')
          const container = element.shadowRoot!.querySelector('.query-params .form-item.optional') as HTMLElement
          const { display } = getComputedStyle(container)
          assert.equal(display, 'flex')
        })

        it('does not render the toggle button for all required', async () => {
          const method = loader.lookupOperation(
            model,
            '/required-query-parameters',
            'get'
          ) as AmfDefinitions.IAmfOperation
          const element = await hideOptionalFixture(method['@id'])
          const toggle = element.shadowRoot!.querySelector('.query-params .toggle-optional-switch')
          assert.notOk(toggle, 'toggle is not rendered')
          const allItems = element.shadowRoot!.querySelectorAll('.query-params .form-item')
          Array.from(allItems).forEach((node) => {
            const { display } = getComputedStyle(node)
            assert.equal(display, 'flex')
          })
        })
      })

      describe('header parameters', () => {
        it('renders the optional toggle button', async () => {
          const method = loader.lookupOperation(model, '/optional-headers', 'get') as AmfDefinitions.IAmfOperation
          const element = await hideOptionalFixture(method['@id'])
          const toggle = element.shadowRoot!.querySelector('.params-section.header .toggle-optional-switch')
          assert.ok(toggle)
        })

        it('optional parameters are hidden', async () => {
          const method = loader.lookupOperation(model, '/optional-headers', 'get') as AmfDefinitions.IAmfOperation
          const element = await hideOptionalFixture(method['@id'])
          const allItems = element.shadowRoot!.querySelectorAll('.params-section.header .form-item.optional')
          Array.from(allItems).forEach((node) => {
            const { display } = getComputedStyle(node)
            assert.equal(display, 'none')
          })
        })

        it('toggles the visibility of the parameters', async () => {
          const method = loader.lookupOperation(model, '/optional-headers', 'get') as AmfDefinitions.IAmfOperation
          const element = await hideOptionalFixture(method['@id'])
          const toggle = element.shadowRoot!.querySelector(
            '.params-section.header .toggle-optional-switch'
          ) as HTMLElement
          toggle.click()
          await nextFrame()
          assert.deepEqual(element.openedOptional, ['header'], 'adds query to the openedOptional')
          const container = element.shadowRoot!.querySelector(
            '.params-section.header .form-item.optional'
          ) as HTMLElement
          const { display } = getComputedStyle(container)
          assert.equal(display, 'flex')
        })

        it('does not render the toggle button for all required', async () => {
          const method = loader.lookupOperation(model, '/required-headers', 'get') as AmfDefinitions.IAmfOperation
          const element = await hideOptionalFixture(method['@id'])
          const toggle = element.shadowRoot!.querySelector('.params-section.header .toggle-optional-switch')
          assert.notOk(toggle, 'toggle is not rendered')
          const allItems = element.shadowRoot!.querySelectorAll('.params-section.header .form-item')
          Array.from(allItems).forEach((node) => {
            const { display } = getComputedStyle(node)
            assert.equal(display, 'flex')
          })
        })
      })
    })

    describe('Body editing', () => {
      describe('Value settings', () => {
        let model: AmfDefinitions.IAmfDocument
        before(async () => {
          model = await loader.getGraph(demoApi)
          store.amf = model
        })

        it('sets value from a RAML example for a JSON body', async () => {
          const method = loader.lookupOperation(model, '/body-types/json', 'post') as AmfDefinitions.IAmfOperation
          const element = await modelFixture(method['@id'])
          const request = await element.serialize()
          const data = JSON.parse(String(request.expects.payload))
          assert.equal(data.name, 'Pawel Psztyc')

          const bodyEditor = element.shadowRoot!.querySelector('http-body-text-editor')!
          assert.equal(bodyEditor.contentType, 'application/json', 'body editor has the content type')
        })

        it('sets value from a RAML example for an XML body', async () => {
          const method = loader.lookupOperation(model, '/body-types/xml', 'post') as AmfDefinitions.IAmfOperation
          const element = await modelFixture(method['@id'])
          const request = await element.serialize()
          const body = String(request.expects.payload)
          assert.include(body, '<name>Pawel Psztyc</name>')

          const bodyEditor = element.shadowRoot!.querySelector('http-body-text-editor')!
          assert.equal(bodyEditor.contentType, 'application/xml', 'body editor has the content type')
        })

        it('sets value from a RAML example for an x-www-form-urlencoded body', async () => {
          const method = loader.lookupOperation(model, '/body-types/form', 'post') as AmfDefinitions.IAmfOperation
          const element = await modelFixture(method['@id'])
          const request = await element.serialize()
          const body = String(request.expects.payload)
          assert.include(body, 'name=Pawel+Psztyc')

          const bodyEditor = element.shadowRoot!.querySelector('http-body-urlencoded-editor')
          assert.ok(bodyEditor, 'renders the specialized form data editor')
        })

        // this can be done by adding support for a new media type in the `api-schema` module.
        // for now an empty FormData instance is created
        it('it has no example values for form data', async () => {
          const method = loader.lookupOperation(
            model,
            '/body-types/multi-parts',
            'post'
          ) as AmfDefinitions.IAmfOperation
          const element = await modelFixture(method['@id'])
          const request = await element.serialize()
          assert.typeOf(request.expects.payload, 'FormData')

          const bodyEditor = element.shadowRoot!.querySelector('http-body-multipart-editor')
          assert.ok(bodyEditor, 'renders the specialized multipart editor')
        })

        it('sets a generated from schema example', async () => {
          const method = loader.lookupOperation(model, '/generated-example', 'post') as AmfDefinitions.IAmfOperation
          const element = await modelFixture(method['@id'])
          const request = await element.serialize()
          const data = JSON.parse(String(request.expects.payload))
          assert.typeOf(data.birthday, 'string', 'a date property is set')
          assert.isNotEmpty(data.birthday, 'a date property has a value')
          assert.equal(data.name, 'John Smith', 'has generated schema value')
        })

        it('renders media type selector', async () => {
          const method = loader.lookupOperation(model, '/generated-example', 'post') as AmfDefinitions.IAmfOperation
          const element = await modelFixture(method['@id'])

          const container = element.shadowRoot!.querySelector('.payload-mime-selector') as HTMLElement
          assert.ok(container, 'has the media selector container')

          const options = container.querySelectorAll('ui-radio')
          assert.lengthOf(options, 3, 'has all defined in the API media types')

          assert.equal(options[0].textContent!.trim(), 'application/json', 'has the application/json option')
          assert.equal(options[1].textContent!.trim(), 'application/xml', 'has the application/xml option')
          assert.equal(
            options[2].textContent!.trim(),
            'application/x-www-form-urlencoded',
            'has the application/x-www-form-urlencoded option'
          )
        })

        it('changes selected mime type', async () => {
          const method = loader.lookupOperation(model, '/generated-example', 'post') as AmfDefinitions.IAmfOperation
          const element = await modelFixture(method['@id'])

          const options = element.shadowRoot!.querySelectorAll(
            '.payload-mime-selector ui-radio'
          ) as NodeListOf<HTMLElement>
          options[1].click()

          await nextFrame()

          const request = await element.serialize()
          const body = String(request.expects.payload)
          assert.include(body, '<url>')

          const bodyEditor = element.shadowRoot!.querySelector('http-body-text-editor')!
          assert.equal(bodyEditor.contentType, 'application/xml', 'body editor has the content type')
        })
      })

      describe('apic-169', () => {
        let model: AmfDefinitions.IAmfDocument
        before(async () => {
          model = await loader.getGraph('apic-169')
          store.amf = model
        })

        it('sets the value with optional and generated', async () => {
          const method = loader.lookupOperation(model, '/new', 'post') as AmfDefinitions.IAmfOperation
          const element = await modelFixture(method['@id'])
          const request = await element.serialize()
          const data = JSON.parse(String(request.expects.payload))
          assert.equal(data.name, 'MuleSoft')
        })
      })

      describe('APIC-480', () => {
        let model: AmfDefinitions.IAmfDocument
        before(async () => {
          model = await loader.getGraph('APIC-480')
          store.amf = model
        })

        it('sets the content type of the operation', async () => {
          const method = loader.lookupOperation(
            model,
            '/accounts/{accountNumber}',
            'patch'
          ) as AmfDefinitions.IAmfOperation
          const element = await modelFixture(method['@id'])
          const request = await element.serialize()
          assert.include(request.expects.headers, 'content-type: application/json')
        })
      })

      describe('APIC-613', () => {
        let model: AmfDefinitions.IAmfDocument
        before(async () => {
          model = await loader.getGraph('APIC-613')
          store.amf = model
        })

        it('should not reset input fields when manipulating them', async () => {
          const method = loader.lookupOperation(model, '/files', 'post') as AmfDefinitions.IAmfOperation
          const element = await modelFixture(method['@id'])

          const editor = element.shadowRoot!.querySelector('http-body-multipart-editor')!
          ;(editor.shadowRoot!.querySelector('.add-param.text-part') as HTMLElement).click()
          // waiting for the input to render.
          await nextFrame()

          const input = editor.shadowRoot!.querySelector('anypoint-input[data-property="name"]') as HTMLInputElement
          input.value = 'Test'
          input.dispatchEvent(new Event('input'))
          input.dispatchEvent(new Event('change'))

          await nextFrame()
          assert.exists(editor.shadowRoot!.querySelector('anypoint-input[data-property="name"]'))
        })
      })
    })
  })

  describe('#allowCustomBaseUri', () => {
    let element: ApiRequestEditorElement
    beforeEach(async () => {
      element = await customBaseUriSlotFixture()
    })

    it('has 1 server by default', () => {
      assert.equal(element.serversCount, 1)
    })

    it('hides server selector with a single server', async () => {
      assert.isTrue(element.serverSelectorHidden)
    })

    it('sets hidden attribute to server selector', async () => {
      const serverSelector = element.shadowRoot!.querySelector('api-server-picker')!
      assert.exists(serverSelector)
      assert.isTrue(serverSelector.hasAttribute('hidden'))
    })

    it('has 2 servers', async () => {
      element.allowCustomBaseUri = true
      await nextFrame()
      assert.equal(element.serversCount, 2)
    })

    it('does not hide server selector', async () => {
      element.allowCustomBaseUri = true
      await nextFrame()
      assert.isFalse(element.serverSelectorHidden)
    })

    it('should set hidden attribute to false in server selector', async () => {
      element.allowCustomBaseUri = true
      await nextFrame()
      const serverSelector = element.shadowRoot!.querySelector('api-server-picker') as HTMLElement
      assert.exists(serverSelector)
      assert.isFalse(serverSelector.hasAttribute('hidden'))
    })
  })

  describe('#noServerSelector', () => {
    it('hides server selector', async () => {
      const element = await noSelectorFixture()
      assert.isTrue(element.serverSelectorHidden)
    })

    it('should set hidden attribute to server selector', async () => {
      const element = await noSelectorFixture()
      const serverSelector = element.shadowRoot!.querySelector('api-server-picker') as HTMLElement
      assert.exists(serverSelector)
      assert.isTrue(serverSelector.hasAttribute('hidden'))
    })

    it('renders server selector at first', async () => {
      const element = await customBaseUriSlotFixture()
      element.allowCustomBaseUri = true
      await nextFrame()
      assert.isFalse(element.serverSelectorHidden)
    })

    it('hides the selector', async () => {
      const element = await customBaseUriSlotFixture()
      element.allowCustomBaseUri = true
      await nextFrame()
      element.noServerSelector = true
      await nextFrame()
      assert.isTrue(element.serverSelectorHidden)
      const serverSelector = element.shadowRoot!.querySelector('api-server-picker') as HTMLElement
      assert.exists(serverSelector)
      assert.isTrue(serverSelector.hasAttribute('hidden'))
    })
  })

  const multiServerApi = 'multi-server'

  function dispatchSelectionEvent(element: HTMLElement, value: string, type: string): void {
    const e = {
      detail: {
        value,
        type,
      },
    }
    const node = element.shadowRoot!.querySelector('api-server-picker') as HTMLElement
    node.dispatchEvent(new CustomEvent('apiserverchanged', e))
  }

  async function changeSelection(element: ApiRequestEditorElement, domainId: string): Promise<void> {
    element.domainId = domainId
    await nextFrame()
  }

  describe('Multi server', () => {
    describe('custom URI selection', () => {
      let model: AmfDefinitions.IAmfDocument
      before(async () => {
        model = await loader.getGraph(multiServerApi)
        store.amf = model
      })

      let element: ApiRequestEditorElement
      beforeEach(async () => {
        element = await modelFixture()
        // This is equivalent to Custom URI being selected, and 'https://www.google.com' being input
        dispatchSelectionEvent(element, 'https://www.google.com', 'custom')
      })

      it('has servers computed', () => {
        assert.lengthOf(element.servers!, 4)
      })

      it('updates serverValue', () => {
        assert.equal(element.serverValue, 'https://www.google.com')
      })

      it('renders selector for custom URI', () => {
        assert.exists(element.shadowRoot!.querySelector('api-server-picker'))
      })

      it('sets effectiveBaseUri to baseUri value', () => {
        element.baseUri = 'https://example.org'
        assert.equal(element.effectiveBaseUri, element.baseUri)
        assert.equal(element.effectiveBaseUri, 'https://example.org')
      })

      it('sets effectiveBaseUri serverValue value', () => {
        assert.equal(element.effectiveBaseUri, element.serverValue)
        assert.equal(element.effectiveBaseUri, 'https://www.google.com')
      })

      it('updates computed server', async () => {
        dispatchSelectionEvent(element, 'https://{customerId}.saas-app.com:{port}/v2', 'server')
        await nextFrame()
        assert.isDefined(element.server)
      })
    })

    describe('from navigation events', () => {
      let model: AmfDefinitions.IAmfDocument
      before(async () => {
        model = await loader.getGraph(multiServerApi)
        store.amf = model
      })

      let element: ApiRequestEditorElement
      beforeEach(async () => {
        element = await modelFixture()
      })

      it('has default number of servers', async () => {
        assert.lengthOf(element.servers!, 4)
      })

      it('computes servers when first navigation', async () => {
        const method = loader.lookupOperation(model, '/default', 'get') as AmfDefinitions.IAmfOperation
        await changeSelection(element, method['@id'])
        assert.lengthOf(element.servers!, 4)
      })

      it('computes servers after subsequent navigation', async () => {
        // default navigation
        await changeSelection(
          element,
          (loader.lookupOperation(model, '/default', 'get') as AmfDefinitions.IAmfOperation)['@id']
        )
        // other endpoint
        await changeSelection(
          element,
          (loader.lookupOperation(model, '/files', 'get') as AmfDefinitions.IAmfOperation)['@id']
        )
        assert.lengthOf(element.servers!, 1)
      })

      it('automatically selects the first available server', async () => {
        await changeSelection(
          element,
          (loader.lookupOperation(model, '/default', 'get') as AmfDefinitions.IAmfOperation)['@id']
        )
        await nextFrame()
        assert.equal(element.serverValue, 'https://{customerId}.saas-app.com:{port}/v2')
      })

      it('auto change selected server', async () => {
        await changeSelection(
          element,
          (loader.lookupOperation(model, '/default', 'get') as AmfDefinitions.IAmfOperation)['@id']
        )
        await changeSelection(
          element,
          (loader.lookupOperation(model, '/files', 'get') as AmfDefinitions.IAmfOperation)['@id']
        )
        assert.equal(element.serverValue, 'https://files.example.com')
      })

      it('keeps server selection when possible', async () => {
        await changeSelection(
          element,
          (loader.lookupOperation(model, '/default', 'get') as AmfDefinitions.IAmfOperation)['@id']
        )

        dispatchSelectionEvent(element, 'https://{region}.api.cognitive.microsoft.com', 'server')

        await changeSelection(
          element,
          (loader.lookupOperation(model, '/copy', 'get') as AmfDefinitions.IAmfOperation)['@id']
        )
        assert.equal(element.serverValue, 'https://{region}.api.cognitive.microsoft.com')
      })

      it('initializes with selected server', async () => {
        const methodId = (loader.lookupOperation(model, '/ping', 'get') as AmfDefinitions.IAmfOperation)['@id']
        element = await modelFixture(methodId)
        await nextFrame()
        assert.lengthOf(element.servers!, 2)
      })
    })
  })

  // TODO: fix me
  describe(`Populating annotated fields`, () => {
    const annotatedParametersApi = 'annotated-parameters'

    let model: AmfDefinitions.IAmfDocument
    before(async () => {
      model = await loader.getGraph(annotatedParametersApi)
      store.amf = model
    })

    let element: ApiRequestEditorElement
    beforeEach(async () => {
      InputCache.globalValues.clear()
      const selected = (loader.lookupOperation(model, '/test', 'get') as AmfDefinitions.IAmfOperation)['@id']
      element = await modelFixture(selected)
    })

    // it('should populate annotated query parameter field', () => {
    //   const detail = { values: [{ annotationName: 'credentialType', annotationValue: 'id', fieldValue: 'test value' }] };
    //   document.dispatchEvent(new CustomEvent('populate_annotated_fields', { detail, bubbles: true }));
    //   const values: string[] = [];
    //   element.parametersValue.forEach((p) => {
    //     if (p.parameter.binding !== 'query') {
    //       return;
    //     }
    //     values[values.length] = InputCache.get(element, p.paramId, false) as string;
    //   })
    //   assert.deepEqual(values, ['', 'test value']);
    // });

    // it('should populate annotated header field', () => {
    //   const detail = { values: [{ annotationName: 'credentialType', annotationValue: 'secret', fieldValue: 'test value' }] };
    //   document.dispatchEvent(new CustomEvent('populate_annotated_fields', { detail, bubbles: true }));
    //   const values: string[] = [];
    //   element.parametersValue.forEach((p) => {
    //     if (p.parameter.binding !== 'header') {
    //       return;
    //     }
    //     values[values.length] = InputCache.get(element, p.paramId, false) as string;
    //   });
    //   assert.deepEqual(values, [ 'test value', '' ]);
    //   const { headers } = await element.serialize();
    //   assert.equal(headers, 'annotatedHeader: test value\nnormalHeader: ');
    // });

    it('should populate annotated query parameter and header fields', async () => {
      const detail = {
        values: [
          { annotationName: 'credentialType', annotationValue: 'id', fieldValue: 'test value 1' },
          { annotationName: 'credentialType', annotationValue: 'secret', fieldValue: 'test value 2' },
        ],
      }
      document.dispatchEvent(new CustomEvent('populate_annotated_fields', { detail, bubbles: true }))
      const serialized = await element.serialize()
      const { headers, url } = serialized.expects
      assert.equal(headers, 'annotatedHeader: test value 2\nnormalHeader: ')
      assert.include(url, 'normalQueryparam=&annotatedQueryParam=test+value+1')
    })
  })

  describe('Authorization', () => {
    const fileName = 'oas-demo'

    describe(`Single method`, () => {
      let model: AmfDefinitions.IAmfDocument
      before(async () => {
        model = await loader.getGraph(fileName)
        store.amf = model
      })

      let element: ApiRequestEditorElement
      beforeEach(async () => {
        const operation = loader.getOperation(model, '/single', 'get')
        element = await modelFixture(operation.id)
      })

      it('sets the security value', async () => {
        assert.typeOf(element.security, 'array', 'has the security')
        assert.lengthOf(element.security!, 1, 'has the single scheme')
        const [scheme] = element.security!
        assert.deepEqual(scheme.types, ['http'], 'has types definition')
        assert.deepEqual(scheme.labels, ['BasicAuth'], 'has labels definition')
        assert.typeOf(scheme.security, 'object', 'has the security definition')
      })

      it('sets the selectedSecurity', async () => {
        assert.isNotEmpty(element.selectedSecurity)
      })

      it('has no selector', () => {
        const node = element.shadowRoot!.querySelector('.auth-selector')
        assert.notOk(node)
      })
    })

    describe(`Single method with union`, () => {
      let model: AmfDefinitions.IAmfDocument
      before(async () => {
        model = await loader.getGraph(fileName)
        store.amf = model
      })

      let element: ApiRequestEditorElement
      beforeEach(async () => {
        const operation = loader.getOperation(model, '/and-and-or-union', 'get')
        element = await modelFixture(operation.id)
      })

      it('sets the security value', async () => {
        assert.typeOf(element.security, 'array', 'has the security')
        assert.lengthOf(element.security!, 2, 'has the both schemes')
        const [scheme1] = element.security!
        assert.deepEqual(scheme1.types, ['Api Key', 'Api Key'], 'has types definition')
        assert.deepEqual(scheme1.labels, ['ApiKeyQuery', 'ApiKeyAuth'], 'has labels definition')
        assert.typeOf(scheme1.security, 'object', 'has the security definition')
      })

      it('has method selector', () => {
        const node = element.shadowRoot!.querySelector('.auth-selector')
        assert.ok(node)
      })

      it('renders combined label', () => {
        const node = element.shadowRoot!.querySelector('ui-list-item[data-label="ApiKeyQuery, ApiKeyAuth"]')
        assert.ok(node)
      })

      it('renders label with names and types', () => {
        const node = element.shadowRoot!.querySelector(
          'ui-list-item[data-label="ApiKeyQuery, ApiKeyAuth"]'
        ) as HTMLElement
        const parts = (node.textContent as string)
          .trim()
          .split('\n')
          .map((item) => item.trim())
        assert.equal(parts[0], 'ApiKeyQuery, ApiKeyAuth')
        assert.equal(parts[1], 'Api Key, Api Key')
      })

      it('renders as single editor', () => {
        const nodes = element.shadowRoot!.querySelectorAll('api-authorization-editor')
        assert.lengthOf(nodes, 1)
      })
    })

    describe(`Multiple unions`, () => {
      let model: AmfDefinitions.IAmfDocument
      before(async () => {
        model = await loader.getGraph(fileName)
        store.amf = model
      })

      let element: ApiRequestEditorElement
      beforeEach(async () => {
        const operation = loader.getOperation(model, '/cross-union', 'get')
        element = await modelFixture(operation.id)
      })

      it('sets the security value', async () => {
        assert.typeOf(element.security, 'array', 'has the security')
        assert.lengthOf(element.security!, 3, 'has the both schemes')
        const [scheme1] = element.security!
        assert.deepEqual(scheme1.types, ['Api Key', 'Api Key'], 'has types definition')
        assert.deepEqual(scheme1.labels, ['ApiKeyQuery', 'ApiKeyAuth'], 'has labels definition')
        assert.typeOf(scheme1.security, 'object', 'has the security definition')
      })

      it('has method selector', () => {
        const node = element.shadowRoot!.querySelector('.auth-selector')
        assert.ok(node)
      })

      it('has no scheme label', () => {
        const node = element.shadowRoot!.querySelector('.auth-selector-label')
        assert.notOk(node)
      })

      it('does not render method labels for API Key', () => {
        const nodes = element.shadowRoot!.querySelectorAll('.auth-label')
        assert.lengthOf(nodes, 0)
      })
    })
  })

  describe('a11y', () => {
    let model: AmfDefinitions.IAmfDocument
    before(async () => {
      model = await loader.getGraph()
      store.amf = model
    })

    // this is result of the a11y audit on API Console
    it('renders the * Required field label when has required query', async () => {
      const method = loader.lookupOperation(model, '/query-params/string', 'get') as AmfDefinitions.IAmfOperation
      const element = await modelFixture(method['@id'])
      const section = element.shadowRoot!.querySelector('.params-section.parameter') as HTMLElement
      const label = section.querySelector('.required-field')
      assert.ok(label, 'has the label')
    })

    // this is result of the a11y audit on API Console
    it('does not render the * Required field label when has required header', async () => {
      const method = loader.lookupOperation(model, '/required-headers', 'get') as AmfDefinitions.IAmfOperation
      const element = await modelFixture(method['@id'])
      const section = element.shadowRoot!.querySelector('.params-section.header') as HTMLElement
      const label = section.querySelector('.required-field')
      assert.ok(label, 'has the label')
    })

    // this is result of the a11y audit on API Console
    it('does not render the * Required field label when has no required header', async () => {
      const method = loader.lookupOperation(model, '/optional-headers', 'get') as AmfDefinitions.IAmfOperation
      const element = await modelFixture(method['@id'])
      const section = element.shadowRoot!.querySelector('.params-section.header') as HTMLElement
      const label = section.querySelector('.required-field')
      assert.notOk(label, 'has no label')
    })
  })
})
