text: const documentationSchema = require('documentation-schema');
  const validate = require('json-schema');
  const documentation = require('../');
  const outputMarkdown = require('../src/output/markdown.js');
  const outputMarkdownAST = require('../src/output/markdown_ast.js');
  const outputHtml = require('../src/output/html.js');
  const normalize = require('./utils').normalize;
  const glob = require('glob');
  const pify = require('pify');
  const path = require('path');
  const fs = require('fs');
  const _ = require('lodash');
  const chdir = require('chdir');
  
  const UPDATE = !!process.env.UPDATE;
  
  function makePOJO(ast) {
    return JSON.parse(JSON.stringify(ast));
  }
  
  function readOptionsFromFile(file) {
    const s = fs.readFileSync(file, 'utf-8');
    const lines = s.split(/\n/, 20);
    for (let i = 0; i < lines.length; i++) {
      const m = lines[i].match(/^\/\/\s+Options:\s*(.+)$/);
      if (m) {
        return JSON.parse(m[1]);
      }
    }
    return {};
  }
  
  if (fs.existsSync(path.join(__dirname, '../.git'))) {
    test('git option', async function() {
      jest.setTimeout(10000); // 10 second timeout. After update flow.js on 0.56 version the test is executed more time.
      const file = path.join(__dirname, './fixture/simple.input.js');
      const result = await documentation.build([file], { github: true });
      normalize(result);
      expect(result).toMatchSnapshot();
  
      const md = await outputMarkdown(result, {});
      expect(md.toString()).toMatchSnapshot();
    });
  }
  
  test('document-exported error', async function() {
    const file = path.join(__dirname, 'fixture', 'document-exported-bad', 'x.js');
    try {
      await documentation.build([file], { documentExported: true });
    } catch (err) {
      expect(err.message.match(/Unable to find the value x/g)).toBeTruthy();
    }
  });
  
  test('external modules option', async function() {
    const result = await documentation.build(
      [path.join(__dirname, 'fixture', 'external.input.js')],
      {
        external: '(external|external/node_modules/*)'
      }
    );
    normalize(result);
    const outputfile = path.join(
      __dirname,
      'fixture',
      '_external-deps-included.json'
    );
    expect(result).toMatchSnapshot();
  });
  
  test('bad input', function() {
    glob
      .sync(path.join(__dirname, 'fixture/bad', '*.input.js'))
      .forEach(function(file) {
        test(path.basename(file), function() {
          return documentation
            .build([file], readOptionsFromFile(file))
            .then(res => {
              expect(res).toBe(undefined);
            })
            .catch(error => {
              // make error a serializable object
              error = JSON.parse(JSON.stringify(error));
              // remove system-specific path
              delete error.filename;
              delete error.codeFrame;
              expect(error).toMatchSnapshot();
            });
        });
      });
  });
  
  describe('html', function() {
    glob
      .sync(path.join(__dirname, 'fixture/html', '*.input.js'))
      .forEach(function(file) {
        test(path.basename(file), async function() {
          const result = await documentation.build(
            [file],
            readOptionsFromFile(file)
          );
          const html = await outputHtml(result, {});
          const clean = html
            .sort((a, b) => a.path > b.path)
            .filter(r => r.path.match(/(html)$/))
            .map(r => r.contents)
            .join('\n');
          expect(clean).toMatchSnapshot();
        });
      });
  });
  
  describe('outputs', function() {
    glob
      .sync(path.join(__dirname, 'fixture', '*.input.js'))
      .forEach(function(file) {
        describe(path.basename(file), async function() {
          let result = null;
          beforeEach(async function() {
            result = await documentation.build([file], readOptionsFromFile(file));
          });
  
          test('markdown', async function() {
            const md = await outputMarkdown(_.cloneDeep(result), {
              markdownToc: true
            });
            expect(result.toString()).toMatchSnapshot();
          });
  
          if (file.match(/es6.input.js/)) {
            test('no markdown TOC', async function() {
              const txt = await outputMarkdown(_.cloneDeep(result), {
                markdownToc: false
              });
              expect(result.toString()).toMatchSnapshot();
            });
          }
  
          test('markdown AST', async function() {
            const ast = await outputMarkdownAST(_.cloneDeep(result), {});
            expect(ast).toMatchSnapshot();
          });
  
          test('JSON', function() {
            normalize(result);
            result.forEach(function(comment) {
              validate(comment, documentationSchema.jsonSchema).errors.forEach(
                function(error) {
                  expect(error).toBeFalsy();
                }
              );
            });
            expect(makePOJO(result)).toMatchSnapshot();
          });
        });
      });
  });
  
  test('highlightAuto md output', async function() {
    const file = path.join(
      __dirname,
      'fixture/auto_lang_hljs/multilanguage.input.js'
    );
    const hljsConfig = {
      hljs: { highlightAuto: true, languages: ['js', 'css', 'html'] }
    };
  
    const result = await documentation.build(file, {});
    const md = await outputMarkdown(result, hljsConfig);
    expect(md.toString()).toMatchSnapshot();
  });
  
  test('config', async function() {
    const file = path.join(__dirname, 'fixture', 'class.input.js');
    const outputfile = path.join(__dirname, 'fixture', 'class.config.output.md');
    const out = await documentation.build([file], {
      config: path.join(__dirname, 'fixture', 'simple.config.yml')
    });
    const md = await outputMarkdown(out, {});
    expect(md).toMatchSnapshot();
  });
  
  test('config with nested sections', async function() {
    const file = path.join(__dirname, 'fixture', 'sections.input.js');
    const out = await documentation.build([file], {
      config: path.join(__dirname, 'fixture', 'sections.config.yml')
    });
    const md = await outputMarkdown(out, {});
    expect(md).toMatchSnapshot();
  });
  
  test('multi-file input', async function() {
    const result = await documentation.build(
      [
        path.join(__dirname, 'fixture', 'simple.input.js'),
        path.join(__dirname, 'fixture', 'simple-two.input.js')
      ],
      {}
    );
    normalize(result);
    expect(result).toMatchSnapshot();
  });
  
  test('accepts simple relative paths', async function() {
    await pify(chdir)(__dirname);
    const data = await documentation.build(
      '__tests__/fixture/simple.input.js',
      {}
    );
    expect(data.length).toBe(1);
  });
  
  test('.lint', async function() {
    await pify(chdir)(__dirname);
    const data = await documentation.lint(
      '__tests__/fixture/simple.input.js',
      {}
    );
    expect(data).toBe('');
  });
  
  test('.lint with bad input', async function() {
    await pify(chdir)(__dirname);
    try {
      await documentation.lint('__tests__/fixture/bad/syntax.input', {
        parseExtension: ['input']
      });
    } catch (err) {
      expect(err).toBeTruthy();
    }
  });
  