<|start_filename|>index.js<|end_filename|>
// @flow
'use strict';

const fs = require('fs-extra');
const path = require('path');
const findUp = require('find-up');
const promisify = require('typeable-promisify');
const onExit = require('signal-exit');
const rimraf = require('rimraf');

const slice = Array.prototype.slice;
const TEMP_PATH = path.join('/tmp', 'jest-fixture-');
const TEMP_DIRS_CREATED = [];

function toFixturesDir(fileParts) {
  return path.join.apply(null, ['__fixtures__'].concat(fileParts));
}

function getFixturePath(cwd /*: string */ /*::, ...fileParts: Array<string> */) {
  let args = Array.prototype.slice.call(arguments, 1);
  return findUp(toFixturesDir(args), { cwd });
}

function getFixturePathSync(cwd /*: string */ /*::, ...fileParts: Array<string> */) {
  let args = Array.prototype.slice.call(arguments, 1);
  return findUp.sync(toFixturesDir(args), { cwd });
}

function createTempDir() {
  return promisify(cb => fs.mkdtemp(TEMP_PATH, cb)).then(tempDir => {
    TEMP_DIRS_CREATED.push(tempDir);
    return tempDir;
  });
}

function createTempDirSync() {
  let tempDir = fs.mkdtempSync(TEMP_PATH);
  TEMP_DIRS_CREATED.push(tempDir);
  return tempDir;
}

function copyDir(sourceDir /*: string */, destDir /*: string */) {
  return promisify(cb => fs.copy(sourceDir, destDir, cb));
}

function copyDirIntoTempDir(sourceDir /*: string */) {
  return createTempDir().then(tempDir => copyDir(sourceDir, tempDir).then(() => (tempDir)));
}

function copyFixtureIntoTempDir(cwd /*: string */ /*::, ...fileParts: Array<string> */) {
  return getFixturePath.apply(null, arguments).then(fixturePath => copyDirIntoTempDir(fixturePath));
}

function cleanupTempDirs() {
  TEMP_DIRS_CREATED.forEach(tempDir => {
    try {
      rimraf.sync(tempDir);
    } catch (err) {}
  });
  TEMP_DIRS_CREATED.length = 0;
}

onExit(cleanupTempDirs);

module.exports = {
  getFixturePath,
  getFixturePathSync,
  createTempDir,
  createTempDirSync,
  copyDir,
  copyDirIntoTempDir,
  copyFixtureIntoTempDir,
  cleanupTempDirs,
};


<|start_filename|>test.js<|end_filename|>
// @flow
'use strict';

const fixtures = require('./');
const fs = require('fs');
const path = require('path');

const FIXTURES_DIR = path.join(__dirname, 'fixtures');
const NESTED_DIR = path.join(FIXTURES_DIR, 'nested');

const FOO_DIR = path.join(FIXTURES_DIR, '__fixtures__', 'foo');
const BAR_DIR = path.join(NESTED_DIR, '__fixtures__', 'bar');

const FOO_FILE_TXT = path.join(FOO_DIR, 'file.txt');

describe('getFixturePath()', () => {
  it('should work in the current dir', () => {
    return fixtures.getFixturePath(NESTED_DIR, 'bar').then(fixturePath => {
      expect(fixturePath).toEqual(BAR_DIR);
    });
  });

  it('should work in the parent dir', () => {
    return fixtures.getFixturePath(NESTED_DIR, 'foo').then(fixturePath => {
      expect(fixturePath).toEqual(FOO_DIR);
    });
  });

  it('should work with a nested file', () => {
    return fixtures.getFixturePath(NESTED_DIR, 'foo', 'file.txt').then(fixturePath => {
      expect(fixturePath).toEqual(FOO_FILE_TXT);
    });
  });
});

describe('getFixturePathSync()', () => {
  it('should work in the current dir', () => {
    let fixturePath = fixtures.getFixturePathSync(NESTED_DIR, 'bar');
    expect(fixturePath).toEqual(BAR_DIR);
  });

  it('should work in the parent dir', () => {
    let fixturePath = fixtures.getFixturePathSync(NESTED_DIR, 'foo');
    expect(fixturePath).toEqual(FOO_DIR);
  });

  it('should work with a nested file', () => {
    let fixturePath = fixtures.getFixturePathSync(NESTED_DIR, 'foo', 'file.txt');
    expect(fixturePath).toEqual(FOO_FILE_TXT);
  });
});

describe('createTempDir', () => {
  it('should create a directory in /tmp', () => {
    return fixtures.createTempDir().then(dirName => {
      expect(dirName.startsWith('/tmp/jest-fixture-')).toBe(true);
      let stat = fs.statSync(dirName);
      expect(stat.isDirectory()).toBe(true);
    });
  });
});

describe('createTempDirSync', () => {
  it('should create a directory in /tmp', () => {
    let dirName = fixtures.createTempDirSync();
    expect(dirName.startsWith('/tmp/jest-fixture-')).toBe(true);
    let stat = fs.statSync(dirName);
    expect(stat.isDirectory()).toBe(true);
  });
});

function assertCopiedFiles(tempDir) {
  expect(fs.lstatSync(path.join(tempDir, 'symlink-to-file')).isSymbolicLink()).toBe(true);
  expect(fs.lstatSync(path.join(tempDir, 'file.txt')).isFile()).toBe(true);
  expect(fs.lstatSync(path.join(tempDir, 'nested')).isDirectory()).toBe(true);
  expect(fs.lstatSync(path.join(tempDir, 'nested', 'nested-file.txt')).isFile()).toBe(true);
}

describe('copyDir', () => {
  it('should copy files into a directory', () => {
    let tempDir = fixtures.createTempDirSync();
    let fixturePath = fixtures.getFixturePathSync(NESTED_DIR, 'bar');

    return fixtures.copyDir(fixturePath, tempDir).then(() => {
      assertCopiedFiles(tempDir);
    });
  });
});

describe('copyDirIntoTempDir', () => {
  it('should copy files into a directory', () => {
    let fixturePath = fixtures.getFixturePathSync(NESTED_DIR, 'bar');
    return fixtures.copyDirIntoTempDir(fixturePath).then(tempDir => {
      assertCopiedFiles(tempDir);
    });
  });
});

describe('copyFixtureIntoTempDir', () => {
  it('should copy files into a directory', () => {
    return fixtures.copyFixtureIntoTempDir(NESTED_DIR, 'bar').then(tempDir => {
      assertCopiedFiles(tempDir);
    });
  });
});

describe('cleanupTempDirs', () => {
  it('should delete all the tmp dirs created with createTempDirSync', () => {
    let tempDir1 = fixtures.createTempDirSync();
    let tempDir2 = fixtures.createTempDirSync();
    fixtures.cleanupTempDirs();
    expect(() => fs.statSync(tempDir1)).toThrow();
    expect(() => fs.statSync(tempDir2)).toThrow();
  });

  it('should delete all the tmp dirs created with createTempDir', () => {
    return fixtures.createTempDir().then(tempDir1 => {
      return fixtures.createTempDir().then(tempDir2 => {
        fixtures.cleanupTempDirs();
        expect(() => fs.statSync(tempDir1)).toThrow();
        expect(() => fs.statSync(tempDir2)).toThrow();
      });
    });
  });

  it('should delete all the tmp dirs created with createTempDir', () => {
    let fixturePath = fixtures.getFixturePathSync(NESTED_DIR, 'bar');
    return fixtures.copyDirIntoTempDir(fixturePath).then(tempDir => {
      fixtures.cleanupTempDirs();
      expect(() => fs.statSync(tempDir)).toThrow();
    });
  });

  it('should delete all the tmp dirs created with copyFixtureIntoTempDir', () => {
    return fixtures.copyFixtureIntoTempDir(NESTED_DIR, 'bar').then(tempDir => {
      fixtures.cleanupTempDirs();
      expect(() => fs.statSync(tempDir)).toThrow();
    });
  });
});
