text: /**
   * Copyright 2016 The AMP HTML Authors. All Rights Reserved.
   *
   * 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 {AmpViewerIntegration} from '../amp-viewer-integration';
  import {Messaging, WindowPortEmulator} from '../messaging.js';
  import {ViewerForTesting} from './viewer-for-testing.js';
  import {getSourceUrl} from '../../../../src/url';
  
  
  describes.sandboxed('AmpViewerIntegration', {}, () => {
    const ampDocSrc = '/test/fixtures/served/ampdoc-with-messaging.html';
    describe('Handshake', function() {
      let viewerEl;
      let viewer;
      let ampDocUrl;
  
      beforeEach(() => {
        const loc = window.location;
        ampDocUrl =
          `${loc.protocol}//iframe.${loc.hostname}:${loc.port}${ampDocSrc}`;
  
        viewerEl = document.createElement('div');
        document.body.appendChild(viewerEl);
        viewer = new ViewerForTesting(viewerEl, '1', ampDocUrl, true);
        return viewer.waitForHandshakeRequest();
      });
  
      afterEach(() => {
        document.body.removeChild(viewerEl);
      });
  
      it('should confirm the handshake', () => {
        console/*OK*/.log('sending handshake response');
        viewer.confirmHandshake();
        return viewer.waitForDocumentLoaded();
      });
  
      it('should handle unload correctly', () => {
        viewer.confirmHandshake();
        viewer.waitForDocumentLoaded().then(() => {
          const stub = sandbox.stub(viewer, 'handleUnload_');
          window.eventListeners.fire({type: 'unload'});
          expect(stub).to.be.calledOnce;
        });
      });
  
  
      describes.realWin('amp-viewer-integration', {
        amp: {
          location: 'https://cdn.ampproject.org/c/s/www.example.com/path',
          params: {
            origin: 'https://example.com',
          },
        },
      }, env => {
        describe('Open Channel', () => {
          class Messaging {
            constructor() {}
            sendRequest() {}
            setup_() {}
            setDefaultHandler() {}
            registerHandler() {}
          }
  
          let win;
          let messaging;
          let ampViewerIntegration;
  
          beforeEach(() => {
            win = document.createElement('div');
            win.document = document.createElement('div');
            ampViewerIntegration = new AmpViewerIntegration(win);
            messaging = new Messaging();
  
          });
  
          it('should start with the correct message', () => {
            const sendRequestSpy = sandbox.stub(messaging, 'sendRequest', () => {
              return Promise.resolve();
            });
  
            ampViewerIntegration.openChannelAndStart_(
              viewer, env.ampdoc, messaging);
  
            const ampdocUrl = env.ampdoc.getUrl();
            const srcUrl = getSourceUrl(ampdocUrl);
  
            expect(sendRequestSpy).to.have.been.calledWith('channelOpen', {
              sourceUrl: srcUrl,
              url: ampdocUrl,
            }, true);
          });
  
          it('should not initiate the Touch Handler', () => {
            sandbox.stub(messaging, 'sendRequest', () => {
              return Promise.resolve();
            });
            const initTouchHandlerStub =
              sandbox.stub(ampViewerIntegration, 'initTouchHandler_');
            ampViewerIntegration.openChannelAndStart_(
              viewer, env.ampdoc, messaging);
  
            expect(initTouchHandlerStub).to.not.be.called;
          });
  
          it('should initiate the Touch Handler', () => {
            sandbox.stub(messaging, 'sendRequest', () => {
              return Promise.resolve();
            });
            sandbox.stub(viewer, 'hasCapability').returns(true);
            const initTouchHandlerStub =
              sandbox.stub(ampViewerIntegration, 'initTouchHandler_');
            ampViewerIntegration.unconfirmedViewerOrigin_ = '';
            ampViewerIntegration.openChannelAndStart_(
              viewer, env.ampdoc, messaging).then(() => {
                expect(initTouchHandlerStub).to.be.called;
              });
          });
        });
      });
    });
  
    describe('Unit Tests for messaging.js', () => {
      const viewerOrigin = 'http://localhost:9876';
      const requestProcessor = function() {
        return Promise.resolve({});
      };
      let messaging;
      let postMessagePromise;
      let postMessageSpy;
  
      beforeEach(() => {
        let postMessageResolve;
        postMessagePromise = new Promise(resolve => {
          postMessageResolve = resolve;
        });
  
        const port = new WindowPortEmulator(
          this.win, viewerOrigin);
        port.addEventListener = function() {};
        port.postMessage = function() {};
  
        postMessageSpy = sandbox.stub(port, 'postMessage', () => {
          postMessageResolve();
        });
  
        messaging = new Messaging(this.win, port);
        messaging.setDefaultHandler(requestProcessor);
      });
  
      it('handleMessage_ should call postMessage correctly', () => {
        const event = {
          source: window,
          origin: viewerOrigin,
          data: {
            app: '__AMPHTML__',
            name: 'message',
            type: 'q',
            requestid: 1,
            rsvp: true,
          },
        };
  
        messaging.handleMessage_(event);
  
        return postMessagePromise.then(function() {
          expect(postMessageSpy).to.have.been.calledOnce;
          expect(postMessageSpy).to.have.been.calledWith({
            app: '__AMPHTML__',
            data: {},
            name: 'message',
            requestid: 1,
            type: 's',
          });
        });
      });
  
      it('handleMessage_ should resolve', () => {
        const event = {
          source: window,
          origin: viewerOrigin,
          data: {
            app: '__AMPHTML__',
            data: null,
            name: 'messageName',
            requestid: 1,
            rsvp: true,
            type: 's',
          },
        };
  
        const resolveSpy = sandbox.stub();
        const rejectSpy = sandbox.stub();
        const waitingForResponse = {'1': {
          resolve: resolveSpy,
          reject: rejectSpy,
        }};
  
        sandbox.stub(messaging, 'waitingForResponse_', waitingForResponse);
        messaging.handleMessage_(event);
  
        expect(resolveSpy).to.have.been.calledOnce;
      });
  
      it('handleMessage_ should reject', () => {
        const event = {
          source: window,
          origin: viewerOrigin,
          data: {
            app: '__AMPHTML__',
            data: {},
            error: 'reason',
            name: null,
            requestid: 1,
            rsvp: true,
            type: 's',
          },
        };
  
        const resolveSpy = sandbox.stub();
        const rejectSpy = sandbox.stub();
        const waitingForResponse = {'1': {
          resolve: resolveSpy,
          reject: rejectSpy,
        }};
  
        const logErrorSpy = sandbox.stub(messaging, 'logError_');
        sandbox.stub(messaging, 'waitingForResponse_', waitingForResponse);
        messaging.handleMessage_(event);
  
        expect(rejectSpy).to.have.been.calledOnce;
  
        expect(logErrorSpy).to.have.been.calledOnce;
  
        expect(logErrorSpy).to.have.been.calledWith(
          'amp-viewer-messaging: handleResponse_ error: ',
          'reason');
      });
  
      it('sendRequest should call postMessage correctly', () => {
        const message = 'message';
        const awaitResponse = false;
        const payload = {};
        messaging.sendRequest(message, payload, awaitResponse);
  
        return postMessagePromise.then(function() {
          expect(postMessageSpy).to.have.been.calledOnce;
          expect(postMessageSpy).to.have.been.calledWith({
            app: '__AMPHTML__',
            data: {},
            name: message,
            requestid: 1,
            rsvp: awaitResponse,
            type: 'q',
          });
        });
      });
  
      it('sendResponse_ should call postMessage correctly', () => {
        const mName = 'name';
        const payload = {};
        const requestId = 1;
        messaging.sendResponse_(requestId, mName, payload);
  
        return postMessagePromise.then(function() {
          expect(postMessageSpy).to.have.been.calledOnce;
          expect(postMessageSpy).to.have.been.calledWith({
            app: '__AMPHTML__',
            data: {},
            name: mName,
            requestid: 1,
            type: 's',
          });
        });
      });
  
      it('sendResponseError_ should call postMessage correctly', () => {
        const mName = 'name';
        const err = new Error('reason');
        const errString = messaging.errorToString_(err);
        const requestId = 1;
        const logErrorSpy = sandbox.stub(messaging, 'logError_');
        messaging.sendResponseError_(requestId, mName, err);
  
        return postMessagePromise.then(function() {
          expect(postMessageSpy).to.have.been.calledOnce;
          expect(postMessageSpy).to.have.been.calledWith({
            app: '__AMPHTML__',
            data: null,
            error: errString,
            name: mName,
            requestid: 1,
            type: 's',
          });
  
          expect(logErrorSpy).to.have.been.calledOnce;
          const state = 'amp-viewer-messaging: sendResponseError_, ' +
            'Message name: name';
          expect(logErrorSpy).to.have.been.calledWith(state, errString);
        });
      });
    });
  });
  