[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/goicco/node-inspector/master/test/ScriptFileStorage.js [Back]  [Original]

var fs = require('fs-extra'),
  path = require('path'),
  expect = require('chai').expect,
  glob = require('glob'),
  launcher = require('./helpers/launcher.js'),
  SessionStub = require('./helpers/SessionStub.js'),
  ScriptFileStorage = require('../lib/ScriptFileStorage.js').ScriptFileStorage,
  ScriptManager = require('../lib/ScriptManager.js').ScriptManager;

var TEMP_FILE = path.join(__dirname, 'fixtures', 'temp.js');
var TEMP_DIR = path.join(__dirname, 'work');
// directory that does not look like a part of a node.js application
var NON_APP_DIR = path.join(__dirname, '..', 'front-end', 'cm');

beforeEach(deleteTemps);
describe('ScriptFileStorage', function() {
  var storage;
  beforeEach(function() {
    storage = createScriptFileStorage();
  });

  it('saves new content without node.js module wrapper', function(done) {
    runLiveEdit(function(debuggerClient, originalScript, runtimeScript) {
      var storage = createScriptFileStorage();
      storage.save(TEMP_FILE, edited(runtimeScript), function(err) {
        if (err) throw err;
        var newScript = fs.readFileSync(TEMP_FILE, { encoding: 'utf-8' });
        expect(newScript).to.equal(edited(originalScript));
        done();
      });
    });
  });

  it('preserves shebang when saving new content', function(done) {
    runLiveEdit(
      function(content) { return '#!/usr/bin/node\n' + content; },
      function(debuggerClient, originalScript, runtimeScript) {
        var storage = createScriptFileStorage();
        storage.save(TEMP_FILE, edited(runtimeScript), function(err) {
          if (err) throw err;
          var newScript = fs.readFileSync(TEMP_FILE, { encoding: 'utf-8' });
          expect(newScript).to.equal(edited(originalScript));
          done();
        });
      }
    );
  });

  it('loads content with node.js module wrapper', function(done) {
    fs.writeFileSync(TEMP_FILE, '/* content */');
    storage.load(TEMP_FILE, function(err, content) {
      if (err) throw err;
      expect(content).to.match(
        /^\(function \(exports, require,.*\) \{ \/\* content \*\/\n\}\);$/);
      done();
    });
  });

  it('loads content without shebang', function(done) {
    fs.writeFileSync(TEMP_FILE, '#!/usr/bin/env/node\n/* content */');
    storage.load(TEMP_FILE, function(err, content) {
      if (err) throw err;
      expect(content).to.not.contain('#!');
      expect(content).to.contain('/* content */');
      done();
    });
  });

  it('finds application root for subdir/app.js by checking package.json file in parent',
    function(done) {
      givenTempFiles('subdir/', 'subdir/app.js', 'package.json');
      storage.findApplicationRoot(
        path.join(TEMP_DIR, 'subdir', 'app.js'),
        expectRootToEqual.bind(this, done, TEMP_DIR)
      );
    }
  );

  it('finds application root for root/app.js with no package.json files around',
    function(done) {
      // If the parent directory of app.js does not contain package.json,
      // it should not be considered as an application root.
      givenTempFiles('root/', 'root/app.js');
      storage.findApplicationRoot(
        path.join(TEMP_DIR, 'root', 'app.js'),
        expectRootToEqual.bind(this, done, path.join(TEMP_DIR, 'root'))
      );
    }
  );

  it('finds application root for root/app.js by checking package.json file in root/',
    function(done) {
      givenTempFiles('root/', 'root/app.js', 'root/package.json', 'package.json');
      storage.findApplicationRoot(
        path.join(TEMP_DIR, 'root', 'app.js'),
        expectRootToEqual.bind(this, done, path.join(TEMP_DIR, 'root'))
      );
    }
  );

  it('finds also files in start directory', function(done) {
    var expectedFiles = givenTempFiles(
      // Globally installed module, e.g. mocha
      'global/',
      'global/runner.js',
      'global/lib/', 'global/lib/module.js',
      // Local application we are developing
      'local/',
      'local/app.js',
      'local/test/', 'local/test/app.js',
      // Other files in a place close to globally installed modules
      'unrelated/',
      'unrelated/file.js'
    );

    givenTempFiles('global/package.json', 'local/package.json');

    // remove unrelated/file.js
    expect(expectedFiles.pop()).to.match(/unrelated[\/\\]file.js$/);

    storage.findAllApplicationScripts(
      path.join(TEMP_DIR, 'local'),
      path.join(TEMP_DIR, 'global', 'runner.js'),
      function(err, files) {
        if (err) throw err;
        expect(files.map(relativeToTemp))
          .to.have.members(expectedFiles.map(relativeToTemp));
        done();
      }
    );
  });

  it('lists only well-known subdirectories when package.json is missing', function(done) {
    var expectedFiles = givenTempFiles(
      'app.js',
      'root.js',
      'lib/helper.js',
      'test/unit.js',
      'node_modules/module/index.js'
    );

    givenTempFiles(
      'extra/file.js'
    );

    storage.findAllApplicationScripts(
      path.join(TEMP_DIR),
      path.join(TEMP_DIR, 'app.js'),
      function(err, files) {
        if (err) throw err;
        expect(files.map(relativeToTemp))
          .to.have.members(expectedFiles.map(relativeToTemp));
        done();
      }
    );
  });

  it('lists all subdirectories when package.json is present', function(done) {
    var expectedFiles = givenTempFiles(
      'app.js',
      'root.js',
      'lib/helper.js',
      'test/unit.js',
      'node_modules/module/index.js',
      'extra/file.js'
    );

    givenTempFiles('package.json');

    storage.findAllApplicationScripts(
      path.join(TEMP_DIR),
      path.join(TEMP_DIR, 'app.js'),
      function(err, files) {
        if (err) throw err;
        expect(files.map(relativeToTemp))
          .to.have.members(expectedFiles.map(relativeToTemp));
        done();
      }
    );
  });

  it('removes duplicate entries from files found', function(done) {
    var expectedFiles = givenTempFiles('app.js');

    storage.findAllApplicationScripts(
      TEMP_DIR,
      path.join(TEMP_DIR, 'app.js'),
      function(err, files) {
        if (err) throw err;
        expect(files.map(relativeToTemp))
          .to.have.members(expectedFiles.map(relativeToTemp));
        expect(files).to.have.length(expectedFiles.length);
        done();
      }
    );
  });

  it('excludes files to hide', function(done) {
    var expectedFiles = givenTempFiles('app.js', 'mod.js').slice(0, 1);
    storage = createScriptFileStorage({hidden: [/mod.js/i]});
    storage.findAllApplicationScripts(
      TEMP_DIR,
      path.join(TEMP_DIR, 'app.js'),
      function(err, files) {
        if (err) throw err;
        expect(files.map(relativeToTemp))
          .to.have.members(expectedFiles.map(relativeToTemp));
        expect(files).to.have.length(expectedFiles.length);
        done();
      }
    );
  });


  it('disables preloading files', function(done) {
    givenTempFiles('app.js', 'mod.js');
    storage = createScriptFileStorage({preload: false});

    storage.findAllApplicationScripts(
      TEMP_DIR,
      path.join(TEMP_DIR, 'app.js'),
      function(err, files) {
        if (err) throw err;
        expect(files).to.have.length(0);
        done();
      }
    );
  });

  function relativeToTemp(p) {
    return path.relative(TEMP_DIR, p);
  }

  function expectRootToEqual(done, expected, err, root) {
    if (err) throw err;
    expect(root).to.equal(expected);
    done();
  }

  function edited(source) {
    return source.replace(';', '; /* edited */');
  }

  function runLiveEdit(transformSource, callback) {
    if (!callback) {
      callback = transformSource;
      transformSource = null;
    }

    var originalScript = createTempFileAsCopyOf('LiveEdit.js', transformSource);
    launcher.startDebugger(TEMP_FILE, function(childProcess, session) {
      getScriptSourceByName(session.debuggerClient, TEMP_FILE, function(source) {
        callback(session.debuggerClient, originalScript, source);
      });
    });
  }

  function createTempFileAsCopyOf(fixture, transform) {
    var sourcePath = path.join(__dirname, 'fixtures', fixture);
    var content = fs.readFileSync(sourcePath, { encoding: 'utf-8' });
    if (transform) content = transform(content);
    fs.writeFileSync(TEMP_FILE, content);
    return content;
  }

  function givenTempFiles() {
    var files = [];
    if (!fs.existsSync(TEMP_DIR)) fs.mkdirSync(TEMP_DIR);
    Array.prototype.forEach.call(arguments, function(f) {
      f = path.join(TEMP_DIR, globPathToNative(f));
      if (isDir(f)) {
        fs.mkdirSync(f);
      } else {
        fs.mkdirpSync(path.dirname(f));
        fs.writeFileSync(f, '');
        files.push(f);
      }
    });
    return files;
  }
});

function createScriptFileStorage(config) {
  var session = new SessionStub();
  session.scriptManager = new ScriptManager(config, session);
  var storage = new ScriptFileStorage(config, session);

  return storage;
}

function globPathToNative(p) {
  return p.split('/').join(path.sep);
}

function getScriptSourceByName(debuggerClient, scriptName, callback) {
  debuggerClient.request(
    'scripts',
    {
      includeSource: true,
      types: 4,
      filter: scriptName
    },
    function(err, result) {
      if (err) throw err;
      callback(result[0].source);
    }
  );
}

function isDir(path) {
  return path.match(/[\/\\]$/);
}

function deleteTemps() {
  if (fs.existsSync(TEMP_FILE)) {
    fs.unlinkSync(TEMP_FILE);
  }

  if (fs.existsSync(TEMP_DIR)) {
    var entries = glob.sync(
      '**',
      {
        cwd: TEMP_DIR,
        dot: true,
        mark: true
      }
    );

    entries = entries
      .map(function(f) {
        return path.join(TEMP_DIR, globPathToNative(f));
      })
      .sort()
      .reverse();

    entries.forEach(function(f) {
      if (isDir(f)) {
        fs.rmdirSync(f);
      } else {
        fs.unlinkSync(f);
      }
    });
  }
}

Web Proxy Viewer  |  New URL  |  Original Page