/**
 * Copyright (c) Microsoft Corporation.
 *
 * 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 { folio } from './cli.fixtures';
import * as http from 'http';
import * as url from 'url';
const { it, describe, expect } = folio;
describe('cli codegen', (test, { browserName, headful }) => {
  test.fixme(browserName === 'firefox' && headful, 'Focus is off');
}, () => {
  it('should click', async ({ page, recorder }) => {
    await recorder.setContentAndWait(`Submit `);
    const selector = await recorder.hoverOverElement('button');
    expect(selector).toBe('text="Submit"');
    const [message] = await Promise.all([
      page.waitForEvent('console'),
      recorder.waitForOutput('click'),
      page.dispatchEvent('button', 'click', { detail: 1 })
    ]);
    expect(recorder.output()).toContain(`
  // Click text="Submit"
  await page.click('text="Submit"');`);
    expect(message.text()).toBe('click');
  });
  it('should not target selector preview by text regexp', async ({ page, recorder }) => {
    await recorder.setContentAndWait(`dummy `);
    // Force highlight.
    await recorder.hoverOverElement('span');
    // Append text after highlight.
    await page.evaluate(() => {
      const div = document.createElement('div');
      div.setAttribute('onclick', "console.log('click')");
      div.textContent = ' Some long text here ';
      document.documentElement.appendChild(div);
    });
    const selector = await recorder.hoverOverElement('div');
    expect(selector).toBe('text=/.*Some long text here.*/');
    // Sanity check that selector does not match our highlight.
    const divContents = await page.$eval(selector, div => div.outerHTML);
    expect(divContents).toBe(`
 Some long text here 
`);
    const [message] = await Promise.all([
      page.waitForEvent('console'),
      recorder.waitForOutput('click'),
      page.dispatchEvent('div', 'click', { detail: 1 })
    ]);
    expect(recorder.output()).toContain(`
  // Click text=/.*Some long text here.*/
  await page.click('text=/.*Some long text here.*/');`);
    expect(message.text()).toBe('click');
  });
  it('should fill', async ({ page, recorder }) => {
    await recorder.setContentAndWait(`link ');
    const selector = await recorder.hoverOverElement('a');
    expect(selector).toBe('text="link"');
    const [popup] = await Promise.all([
      page.context().waitForEvent('page'),
      recorder.waitForOutput('waitForEvent'),
      page.dispatchEvent('a', 'click', { detail: 1 })
    ]);
    expect(recorder.output()).toContain(`
  // Click text="link"
  const [page1] = await Promise.all([
    page.waitForEvent('popup'),
    page.click('text="link"')
  ]);`);
    expect(popup.url()).toBe('about:blank');
  });
  it('should assert navigation', async ({ page, recorder }) => {
    await recorder.setContentAndWait(`link `);
    const selector = await recorder.hoverOverElement('a');
    expect(selector).toBe('text="link"');
    await Promise.all([
      page.waitForNavigation(),
      recorder.waitForOutput('assert'),
      page.dispatchEvent('a', 'click', { detail: 1 })
    ]);
    expect(recorder.output()).toContain(`
  // Click text="link"
  await page.click('text="link"');
  // assert.equal(page.url(), 'about:blank#foo');`);
    expect(page.url()).toContain('about:blank#foo');
  });
  it('should await navigation', async ({ page, recorder }) => {
    await recorder.setContentAndWait(`link `);
    const selector = await recorder.hoverOverElement('a');
    expect(selector).toBe('text="link"');
    await Promise.all([
      page.waitForNavigation(),
      recorder.waitForOutput('waitForNavigation'),
      page.dispatchEvent('a', 'click', { detail: 1 })
    ]);
    expect(recorder.output()).toContain(`
  // Click text="link"
  await Promise.all([
    page.waitForNavigation(/*{ url: 'about:blank#foo' }*/),
    page.click('text="link"')
  ]);`);
    expect(page.url()).toContain('about:blank#foo');
  });
  it('should contain open page', async ({ recorder }) => {
    await recorder.setContentAndWait(``);
    expect(recorder.output()).toContain(`const page = await context.newPage();`);
  });
  it('should contain second page', async ({ contextWrapper, recorder }) => {
    await recorder.setContentAndWait(``);
    await contextWrapper.context.newPage();
    await recorder.waitForOutput('page1');
    expect(recorder.output()).toContain('const page1 = await context.newPage();');
  });
  it('should contain close page', async ({ contextWrapper, recorder }) => {
    await recorder.setContentAndWait(``);
    await contextWrapper.context.newPage();
    await recorder.page.close();
    await recorder.waitForOutput('page.close();');
  });
  it('should not lead to an error if /html gets clicked', async ({ contextWrapper, recorder }) => {
    await recorder.setContentAndWait('');
    await contextWrapper.context.newPage();
    const errors: any[] = [];
    recorder.page.on('pageerror', e => errors.push(e));
    await recorder.page.evaluate(() => document.querySelector('body').remove());
    const selector = await recorder.hoverOverElement('html');
    expect(selector).toBe('/html');
    await recorder.page.close();
    await recorder.waitForOutput('page.close();');
    expect(errors.length).toBe(0);
  });
  it('should upload a single file', async ({ page, recorder }) => {
    await recorder.setContentAndWait(`
    
  `);
    await page.focus('input[type=file]');
    await page.setInputFiles('input[type=file]', 'test/assets/file-to-upload.txt');
    await page.click('input[type=file]');
    await recorder.waitForOutput('setInputFiles');
    expect(recorder.output()).toContain(`
  // Upload file-to-upload.txt
  await page.setInputFiles('input[type="file"]', 'file-to-upload.txt');`);
  });
  it('should upload multiple files', async ({ page, recorder }) => {
    await recorder.setContentAndWait(`
    
  `);
    await page.focus('input[type=file]');
    await page.setInputFiles('input[type=file]', ['test/assets/file-to-upload.txt', 'test/assets/file-to-upload-2.txt']);
    await page.click('input[type=file]');
    await recorder.waitForOutput('setInputFiles');
    expect(recorder.output()).toContain(`
  // Upload file-to-upload.txt, file-to-upload-2.txt
  await page.setInputFiles('input[type="file"]', ['file-to-upload.txt', 'file-to-upload-2.txt']);`);
  });
  it('should clear files', async ({ page, recorder }) => {
    await recorder.setContentAndWait(`
    
  `);
    await page.focus('input[type=file]');
    await page.setInputFiles('input[type=file]', 'test/assets/file-to-upload.txt');
    await page.setInputFiles('input[type=file]', []);
    await page.click('input[type=file]');
    await recorder.waitForOutput('setInputFiles');
    expect(recorder.output()).toContain(`
  // Clear selected files
  await page.setInputFiles('input[type="file"]', []);`);
  });
  it('should download files', async ({ page, recorder, httpServer }) => {
    httpServer.setHandler((req: http.IncomingMessage, res: http.ServerResponse) => {
      const pathName = url.parse(req.url!).path;
      if (pathName === '/download') {
        res.setHeader('Content-Type', 'application/octet-stream');
        res.setHeader('Content-Disposition', 'attachment; filename=file.txt');
        res.end(`Hello world`);
      } else {
        res.setHeader('Content-Type', 'text/html; charset=utf-8');
        res.end('');
      }
    });
    await recorder.setContentAndWait(`
      Download 
    `, httpServer.PREFIX);
    await recorder.hoverOverElement('text=Download');
    await Promise.all([
      page.waitForEvent('download'),
      page.click('text=Download')
    ]);
    await recorder.waitForOutput('page.click');
    expect(recorder.output()).toContain(`
  // Click text="Download"
  const [download] = await Promise.all([
    page.waitForEvent('download'),
    page.click('text="Download"')
  ]);`);
  });
  it('should handle dialogs', async ({ page, recorder }) => {
    await recorder.setContentAndWait(`
    click me 
    `);
    await recorder.hoverOverElement('button');
    page.once('dialog', async dialog => {
      await dialog.dismiss();
    });
    await page.click('text="click me"');
    await recorder.waitForOutput('page.once');
    expect(recorder.output()).toContain(`
  // Click text="click me"
  page.once('dialog', dialog => {
    console.log(\`Dialog message: $\{dialog.message()}\`);
    dialog.dismiss().catch(() => {});
  });
  await page.click('text="click me"')`);
  });
  it('should handle history.postData', async ({ page, recorder, httpServer }) => {
    httpServer.setHandler((req: http.IncomingMessage, res: http.ServerResponse) => {
      res.setHeader('Content-Type', 'text/html; charset=utf-8');
      res.end('Hello world');
    });
    await recorder.setContentAndWait(`
    `, httpServer.PREFIX);
    for (let i = 1; i < 3; ++i) {
      await page.evaluate('pushState()');
      await recorder.waitForOutput(`seqNum=${i}`);
      expect(recorder.output()).toContain(`await page.goto('${httpServer.PREFIX}/#seqNum=${i}');`);
    }
  });
  it('should record open in a new tab with url', (test, { browserName }) => {
    test.fixme(browserName === 'webkit', 'Ctrl+click does not open in new tab on WebKit');
  }, async ({ page, recorder, browserName, platform }) => {
    await recorder.setContentAndWait(`link `);
    const selector = await recorder.hoverOverElement('a');
    expect(selector).toBe('text="link"');
    await page.click('a', { modifiers: [ platform === 'darwin' ? 'Meta' : 'Control'] });
    await recorder.waitForOutput('page1');
    if (browserName === 'chromium') {
      expect(recorder.output()).toContain(`
  // Open new page
  const page1 = await context.newPage();
  page1.goto('about:blank?foo');`);
    } else if (browserName === 'firefox') {
      expect(recorder.output()).toContain(`
  // Click text="link"
  const [page1] = await Promise.all([
    page.waitForEvent('popup'),
    page.click('text="link"', {
      modifiers: ['${platform === 'darwin' ? 'Meta' : 'Control'}']
    })
  ]);`);
    }
  });
  it('should not clash pages', (test, { browserName }) => {
    test.fixme(browserName === 'firefox', 'Times out on Firefox, maybe the focus issue');
  }, async ({ page, recorder }) => {
    const [popup1] = await Promise.all([
      page.context().waitForEvent('page'),
      page.evaluate(`window.open('about:blank')`)
    ]);
    await recorder.setPageContentAndWait(popup1, '
      
    `);
    const messages: any[] = [];
    page.on('console', message => messages.push(message.text()));
    await Promise.all([
      page.click('button'),
      recorder.waitForOutput('page.click')
    ]);
    expect(messages).toEqual(['mousedown', 'mouseup', 'click']);
  });
  it('should update hover model on action', async ({ page, recorder }) => {
    await recorder.setContentAndWait(`