Repository: ember-cli/ember-try
Pull request #409 (2019-10-17 16:05:09)

Add support for using yarn.lock file
Currently, ember-try is running yarn with the --no-lockfile option, which will install packages whose version may differ from the actual current yarn.lock file in the project. To get a true dependency environment during testing, this PR aims to add support for using the project's yarn.lock file when using ember-try by adding a config flag called useYarnLockFile that users can pass in to determine whether to use the project's yarn.lock file.

codecov[bot]: # [Codecov](https://codecov.io/gh/ember-cli/ember-try/pull/409?src=pr&el=h1) Report
> Merging [#409](https://codecov.io/gh/ember-cli/ember-try/pull/409?src=pr&el=desc) into [master](https://codecov.io/gh/ember-cli/ember-try/commit/57d9ea2597a222f8b5b9952f20f3cab615b51d33?src=pr&el=desc) will **increase** coverage by `0.03%`.
> The diff coverage is `100%`.

[![Impacted file tree graph](https://codecov.io/gh/ember-cli/ember-try/pull/409/graphs/tree.svg?width=650&token=5fmkpw9NH2&height=150&src=pr)](https://codecov.io/gh/ember-cli/ember-try/pull/409?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #409      +/-   ##
==========================================
+ Coverage   96.72%   96.76%   +0.03%     
==========================================
  Files          17       17              
  Lines         550      556       +6     
==========================================
+ Hits          532      538       +6     
  Misses         18       18
```


| [Impacted Files](https://codecov.io/gh/ember-cli/ember-try/pull/409?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [lib/utils/dependency-manager-adapter-factory.js](https://codecov.io/gh/ember-cli/ember-try/pull/409/diff?src=pr&el=tree#diff-bGliL3V0aWxzL2RlcGVuZGVuY3ktbWFuYWdlci1hZGFwdGVyLWZhY3RvcnkuanM=) | `95.45% <100%> (ø)` | :arrow_up: |
| [lib/dependency-manager-adapters/npm.js](https://codecov.io/gh/ember-cli/ember-try/pull/409/diff?src=pr&el=tree#diff-bGliL2RlcGVuZGVuY3ktbWFuYWdlci1hZGFwdGVycy9ucG0uanM=) | `100% <100%> (ø)` | :arrow_up: |
| [lib/dependency-manager-adapters/workspace.js](https://codecov.io/gh/ember-cli/ember-try/pull/409/diff?src=pr&el=tree#diff-bGliL2RlcGVuZGVuY3ktbWFuYWdlci1hZGFwdGVycy93b3Jrc3BhY2UuanM=) | `100% <100%> (ø)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/ember-cli/ember-try/pull/409?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/ember-cli/ember-try/pull/409?src=pr&el=footer). Last update [57d9ea2...87b0106](https://codecov.io/gh/ember-cli/ember-try/pull/409?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

rwjblue: I chatted with @kategengler, she suggested we use `buildManagerOptions` as the function name instead of my original proposal of `buildNpmOptions()`.
huyphamily: I see...so if someone has buildManagerOptions in their config, then we use that config instead of the default. If shrinkwrap or yarn.lock files are detected, then we back up those files and restore accordingly. I can make that change.
rwjblue: Ya, exactly

Patch:
diff --git a/README.md b/README.md
index a31b58c..fb0dd1a 100644
--- a/README.md
+++ b/README.md
@@ -126,6 +126,15 @@ module.exports = function() {
       dependencies will be restored to their prior state.
     */
     useYarn: true,
+
+    /*
+      buildManagerOptions allows you to opt-out of the default options such as `--ignore-engines --no-lockfile`.
+      The buildManagerOptions function is aware of each scenario so you can customize your options.
+    */
+    buildManagerOptions(scenario) {
+      return ['--ignore-engines'];
+    }
+
     scenarios: [
       {
         name: 'Ember 1.10 with ember-data',
diff --git a/lib/dependency-manager-adapters/npm.js b/lib/dependency-manager-adapters/npm.js
index af30f86..12fdca2 100644
--- a/lib/dependency-manager-adapters/npm.js
+++ b/lib/dependency-manager-adapters/npm.js
@@ -16,11 +16,16 @@ module.exports = CoreObject.extend({
   },
   useYarnCommand: false,
   yarnLock: 'yarn.lock',
+  yarnLockBackupFileName: 'yarn.lock.ember-try',
   configKey: 'npm',
   packageJSON: 'package.json',
   packageJSONBackupFileName: 'package.json.ember-try',
   nodeModules: 'node_modules',
   nodeModulesBackupLocation: '.node_modules.ember-try',
+  npmShrinkWrap: 'npm-shrinkwrap.json',
+  npmShrinkWrapBackupFileName: 'npm-shrinkwrap.json.ember-try',
+  packageLock: 'package-lock.json',
+  packageLockBackupFileName: 'package-lock.json.ember-try',
   setup(options) {
     if (!options) {
       options = {};
@@ -33,7 +38,7 @@ module.exports = CoreObject.extend({
 
     adapter.applyDependencySet(depSet);
 
-    return adapter._install().then(() => {
+    return adapter._install(depSet).then(() => {
       let deps = extend({}, depSet.dependencies || {}, depSet.devDependencies || {});
       let currentDeps = Object.keys(deps).map((dep) => {
         return {
@@ -58,6 +63,18 @@ module.exports = CoreObject.extend({
       let cleanupTasks = [rimraf(path.join(adapter.cwd, adapter.packageJSONBackupFileName)),
         rimraf(path.join(adapter.cwd, adapter.nodeModulesBackupLocation))];
 
+      if (fs.existsSync(path.join(this.cwd, this.yarnLockBackupFileName))) {
+        cleanupTasks.push(rimraf(path.join(adapter.cwd, adapter.yarnLockBackupFileName)));
+      }
+
+      if (fs.existsSync(path.join(this.cwd, this.npmShrinkWrapBackupFileName))) {
+        cleanupTasks.push(rimraf(path.join(adapter.cwd, adapter.npmShrinkWrapBackupFileName)));
+      }
+
+      if (fs.existsSync(path.join(this.cwd, this.packageLockBackupFileName))) {
+        cleanupTasks.push(rimraf(path.join(adapter.cwd, adapter.packageLockBackupFileName)));
+      }
+
       return RSVP.all(cleanupTasks);
     }).catch((e) => {
       console.log('Error cleaning up npm scenario:', e); // eslint-disable-line no-console
@@ -82,26 +99,35 @@ module.exports = CoreObject.extend({
       return null;
     }
   },
-  _install() {
+  _install(depSet) {
     let adapter = this;
     let mgrOptions = this.managerOptions || [];
+    let cmd = this.useYarnCommand ? 'yarn' : 'npm';
 
-    debug('Run npm install with options %s', mgrOptions);
+    // buildManagerOptions overrides all default
+    if (typeof this.buildManagerOptions === 'function') {
+      mgrOptions = this.buildManagerOptions(depSet);
 
-    let cmd = this.useYarnCommand ? 'yarn' : 'npm';
-    if (this.useYarnCommand) {
-      if (mgrOptions.indexOf('--no-lockfile') === -1) {
-        mgrOptions = mgrOptions.concat(['--no-lockfile']);
+      if (!Array.isArray(mgrOptions)) {
+        throw new Error('buildManagerOptions must return an array of options');
       }
-      // npm warns on incompatible engines
-      // yarn errors, not a good experience
-      if (mgrOptions.indexOf('--ignore-engines') === -1) {
-        mgrOptions = mgrOptions.concat(['--ignore-engines']);
+    } else {
+      if (this.useYarnCommand) {
+        if (mgrOptions.indexOf('--no-lockfile') === -1) {
+          mgrOptions = mgrOptions.concat(['--no-lockfile']);
+        }
+        // npm warns on incompatible engines
+        // yarn errors, not a good experience
+        if (mgrOptions.indexOf('--ignore-engines') === -1) {
+          mgrOptions = mgrOptions.concat(['--ignore-engines']);
+        }
+      } else if (mgrOptions.indexOf('--no-shrinkwrap') === -1) {
+        mgrOptions = mgrOptions.concat(['--no-shrinkwrap']);
       }
-    } else if (mgrOptions.indexOf('--no-shrinkwrap') === -1) {
-      mgrOptions = mgrOptions.concat(['--no-shrinkwrap']);
     }
 
+    debug('Run npm/yarn install with options %s', mgrOptions);
+
     return this.run(cmd, [].concat(['install'], mgrOptions), { cwd: this.cwd }).then(() => {
       if (!adapter.useYarnCommand) {
         return adapter.run('npm', ['--version'], { cwd: this.cwd, stdio: 'pipe' }).then((res) => {
@@ -171,6 +197,21 @@ module.exports = CoreObject.extend({
         path.join(this.cwd, this.nodeModules), { clobber: true }),
     ];
 
+    if (fs.existsSync(path.join(this.cwd, this.yarnLockBackupFileName))) {
+      restoreTasks.push(copy(path.join(this.cwd, this.yarnLockBackupFileName),
+        path.join(this.cwd, this.yarnLock)));
+    }
+
+    if (fs.existsSync(path.join(this.cwd, this.npmShrinkWrapBackupFileName))) {
+      restoreTasks.push(copy(path.join(this.cwd, this.npmShrinkWrapBackupFileName),
+        path.join(this.cwd, this.npmShrinkWrap)));
+    }
+
+    if (fs.existsSync(path.join(this.cwd, this.packageLockBackupFileName))) {
+      restoreTasks.push(copy(path.join(this.cwd, this.packageLockBackupFileName),
+        path.join(this.cwd, this.packageLock)));
+    }
+
     return RSVP.all(restoreTasks);
   },
   _backupOriginalDependencies() {
@@ -184,6 +225,21 @@ module.exports = CoreObject.extend({
       copy(path.join(this.cwd, this.nodeModules),
         path.join(this.cwd, this.nodeModulesBackupLocation), { clobber: true })];
 
+    if (fs.existsSync(path.join(this.cwd, this.yarnLock))) {
+      backupTasks.push(copy(path.join(this.cwd, this.yarnLock),
+        path.join(this.cwd, this.yarnLockBackupFileName)));
+    }
+
+    if (fs.existsSync(path.join(this.cwd, this.npmShrinkWrap))) {
+      backupTasks.push(copy(path.join(this.cwd, this.npmShrinkWrap),
+        path.join(this.cwd, this.npmShrinkWrapBackupFileName)));
+    }
+
+    if (fs.existsSync(path.join(this.cwd, this.packageLock))) {
+      backupTasks.push(copy(path.join(this.cwd, this.packageLock),
+        path.join(this.cwd, this.packageLockBackupFileName)));
+    }
+
     return RSVP.all(backupTasks);
   },
 });
diff --git a/lib/dependency-manager-adapters/workspace.js b/lib/dependency-manager-adapters/workspace.js
index baa6056..b5eb79f 100644
--- a/lib/dependency-manager-adapters/workspace.js
+++ b/lib/dependency-manager-adapters/workspace.js
@@ -47,6 +47,7 @@ module.exports = CoreObject.extend({
         run: this.run,
         managerOptions: this.managerOptions,
         useYarnCommand: true,
+        buildManagerOptions: this.buildManagerOptions,
       });
     });
 
@@ -59,7 +60,7 @@ module.exports = CoreObject.extend({
       adapter.applyDependencySet(depSet);
     });
 
-    return this._install().then(() => {
+    return this._install(depSet).then(() => {
       let deps = extend({}, depSet.dependencies || {}, depSet.devDependencies || {});
       let currentDeps = Object.keys(deps).map((dep) => {
         return {
@@ -80,20 +81,29 @@ module.exports = CoreObject.extend({
     return RSVP.all(this._packageAdapters.map(adapter => adapter.cleanup()));
   },
 
-  _install() {
+  _install(depSet) {
     let mgrOptions = this.managerOptions || [];
 
-    debug('Run yarn install with options %s', mgrOptions);
-
-    if (mgrOptions.indexOf('--no-lockfile') === -1) {
-      mgrOptions = mgrOptions.concat(['--no-lockfile']);
-    }
-    // npm warns on incompatible engines
-    // yarn errors, not a good experience
-    if (mgrOptions.indexOf('--ignore-engines') === -1) {
-      mgrOptions = mgrOptions.concat(['--ignore-engines']);
+    // buildManagerOptions overrides all default
+    if (typeof this.buildManagerOptions === 'function') {
+      mgrOptions = this.buildManagerOptions(depSet);
+
+      if (!Array.isArray(mgrOptions)) {
+        throw new Error('buildManagerOptions must return an array of options');
+      }
+    } else {
+      if (mgrOptions.indexOf('--no-lockfile') === -1) {
+        mgrOptions = mgrOptions.concat(['--no-lockfile']);
+      }
+      // npm warns on incompatible engines
+      // yarn errors, not a good experience
+      if (mgrOptions.indexOf('--ignore-engines') === -1) {
+        mgrOptions = mgrOptions.concat(['--ignore-engines']);
+      }
     }
 
+    debug('Run yarn install with options %s', mgrOptions);
+
     return this.run('yarn', [].concat(['install'], mgrOptions), { cwd: this.cwd });
   },
 
diff --git a/lib/utils/dependency-manager-adapter-factory.js b/lib/utils/dependency-manager-adapter-factory.js
index f2c159c..b524dd4 100644
--- a/lib/utils/dependency-manager-adapter-factory.js
+++ b/lib/utils/dependency-manager-adapter-factory.js
@@ -31,11 +31,12 @@ module.exports = {
         new WorkspaceAdapter({
           cwd: root,
           managerOptions: config.npmOptions,
-          useYarnCommand: config.useYarn
+          useYarnCommand: config.useYarn,
+          buildManagerOptions: config.buildManagerOptions
         })
       );
     } else if (hasNpm || hasBower) {
-      adapters.push(new NpmAdapter({ cwd: root, managerOptions: config.npmOptions, useYarnCommand: config.useYarn }));
+      adapters.push(new NpmAdapter({ cwd: root, managerOptions: config.npmOptions, useYarnCommand: config.useYarn, buildManagerOptions: config.buildManagerOptions }));
       adapters.push(new BowerAdapter({ cwd: root, managerOptions: config.bowerOptions }));
     }
 


Test patch:
diff --git a/test/dependency-manager-adapters/npm-adapter-test.js b/test/dependency-manager-adapters/npm-adapter-test.js
index 8879bbb..239a747 100644
--- a/test/dependency-manager-adapters/npm-adapter-test.js
+++ b/test/dependency-manager-adapters/npm-adapter-test.js
@@ -39,6 +39,24 @@ describe('npmAdapter', () => {
         assertFileContainsJSON(path.join(tmpdir, '.node_modules.ember-try/prove-it.json'), { originalNodeModules: true });
       });
     });
+
+    it('backs up the yarn.lock file, npm-shrinkwrap.json and package-lock.json if they exist', () => {
+      fs.mkdirSync('node_modules');
+      writeJSONFile('node_modules/prove-it.json', { originalNodeModules: true });
+      writeJSONFile('package.json', { originalPackageJSON: true });
+      writeJSONFile('yarn.lock', { originalYarnLock: true });
+      writeJSONFile('npm-shrinkwrap.json', { originalNpmShrinkWrap: true });
+      writeJSONFile('package-lock.json', { originalPackageLock: true });
+      return new NpmAdapter({
+        cwd: tmpdir,
+      }).setup().then(() => {
+        assertFileContainsJSON(path.join(tmpdir, 'package.json.ember-try'), { originalPackageJSON: true });
+        assertFileContainsJSON(path.join(tmpdir, '.node_modules.ember-try/prove-it.json'), { originalNodeModules: true });
+        assertFileContainsJSON(path.join(tmpdir, 'yarn.lock.ember-try'), { originalYarnLock: true });
+        assertFileContainsJSON(path.join(tmpdir, 'npm-shrinkwrap.json.ember-try'), { originalNpmShrinkWrap: true });
+        assertFileContainsJSON(path.join(tmpdir, 'package-lock.json.ember-try'), { originalPackageLock: true });
+      });
+    });
   });
 
   describe('#_install', () => {
@@ -127,6 +145,46 @@ describe('npmAdapter', () => {
           expect(runCount).to.equal(2);
         });
       });
+
+      it('uses buildManagerOptions for npm commands', () => {
+        writeJSONFile('package.json', fixturePackage);
+        let runCount = 0;
+        let stubbedRun = generateMockRun([{
+          command: 'npm install --flat',
+          callback() {
+            runCount++;
+            return RSVP.resolve();
+          },
+        }, {
+          command: 'npm --version',
+          callback() {
+            runCount++;
+            return RSVP.resolve({stdout: '5.7.1'});
+          },
+        }], { allowPassthrough: false });
+
+        return new NpmAdapter({
+          cwd: tmpdir,
+          run: stubbedRun,
+          buildManagerOptions: function() {
+            return ['--flat'];
+          },
+        })._install().then(() => {
+          expect(runCount).to.equal(2, 'npm install should run with buildManagerOptions');
+        });
+      });
+
+      it('throws an error if buildManagerOptions does not return an array', () => {
+        expect(() => {
+          new NpmAdapter({
+            cwd: tmpdir,
+            run: () => {},
+            buildManagerOptions: function() {
+              return 'string';
+            },
+          })._install()
+        }).to.throw(/buildManagerOptions must return an array of options/);
+      });
     });
 
     describe('with yarn', () => {
@@ -171,6 +229,42 @@ describe('npmAdapter', () => {
           expect(runCount).to.equal(1, 'Only yarn install should run with manager options');
         });
       });
+
+      it('uses buildManagerOptions for yarn commands', () => {
+        writeJSONFile('package.json', fixturePackage);
+        let runCount = 0;
+        let stubbedRun = generateMockRun([{
+          command: 'yarn install --flat',
+          callback() {
+            runCount++;
+            return RSVP.resolve();
+          },
+        }], { allowPassthrough: false });
+
+        return new NpmAdapter({
+          cwd: tmpdir,
+          run: stubbedRun,
+          useYarnCommand: true,
+          buildManagerOptions: function() {
+            return ['--flat'];
+          },
+        })._install().then(() => {
+          expect(runCount).to.equal(1, 'Only yarn install should run with buildManagerOptions');
+        });
+      });
+
+      it('throws an error if buildManagerOptions does not return an array', () => {
+        expect(() => {
+          new NpmAdapter({
+            cwd: tmpdir,
+            run: () => {},
+            useYarnCommand: true,
+            buildManagerOptions: function() {
+              return 'string';
+            },
+          })._install()
+        }).to.throw(/buildManagerOptions must return an array of options/);
+      });
     });
   });
 
@@ -185,6 +279,26 @@ describe('npmAdapter', () => {
         assertFileContainsJSON(path.join(tmpdir, 'node_modules/prove-it.json'), { originalNodeModules: true });
       });
     });
+
+    it('replaces the yarn.lock, npm-shrinkwrap.json and package-lock.json with the backed up version if they exist', () => {
+      writeJSONFile('package.json.ember-try', { originalPackageJSON: true });
+      writeJSONFile('package.json', { originalPackageJSON: false });
+      fs.mkdirSync('.node_modules.ember-try');
+      writeJSONFile('.node_modules.ember-try/prove-it.json', { originalNodeModules: true });
+      writeJSONFile('yarn.lock.ember-try', { originalYarnLock: true });
+      writeJSONFile('yarn.lock', { originalYarnLock: false });
+      writeJSONFile('npm-shrinkwrap.json.ember-try', { originalNpmShrinkWrap: true });
+      writeJSONFile('npm-shrinkwrap.json', { originalNpmShrinkWrap: false });
+      writeJSONFile('package-lock.json.ember-try', { originalPackageLock: true });
+      writeJSONFile('package-lock.json', { originalPackageLock: false });
+      return new NpmAdapter({ cwd: tmpdir })._restoreOriginalDependencies().then(() => {
+        assertFileContainsJSON(path.join(tmpdir, 'package.json'), { originalPackageJSON: true });
+        assertFileContainsJSON(path.join(tmpdir, 'node_modules/prove-it.json'), { originalNodeModules: true });
+        assertFileContainsJSON(path.join(tmpdir, 'yarn.lock'), { originalYarnLock: true });
+        assertFileContainsJSON(path.join(tmpdir, 'npm-shrinkwrap.json'), { originalNpmShrinkWrap: true });
+        assertFileContainsJSON(path.join(tmpdir, 'package-lock.json'), { originalPackageLock: true });
+      });
+    });
   });
 
   describe('#_packageJSONForDependencySet', () => {
diff --git a/test/dependency-manager-adapters/workspace-adapter-test.js b/test/dependency-manager-adapters/workspace-adapter-test.js
index e145aa3..090c487 100644
--- a/test/dependency-manager-adapters/workspace-adapter-test.js
+++ b/test/dependency-manager-adapters/workspace-adapter-test.js
@@ -44,6 +44,26 @@ describe('workspaceAdapter', () => {
       });
     });
 
+    it('backs up the yarn.lock file, npm-shrinkwrap.json and package-lock.json if they exist', () => {
+      fs.ensureDirSync('packages/test/node_modules');
+
+      writeJSONFile('packages/test/package.json', { originalPackageJSON: true });
+      writeJSONFile('packages/test/node_modules/prove-it.json', { originalNodeModules: true });
+      writeJSONFile('packages/test/yarn.lock', { originalYarnLock: true });
+      writeJSONFile('packages/test/npm-shrinkwrap.json', { originalNpmShrinkWrap: true });
+      writeJSONFile('packages/test/package-lock.json', { originalPackageLock: true });
+      return new WorkspaceAdapter({
+        cwd: tmpdir,
+        useYarnCommand: true,
+      }).setup().then(() => {
+        assertFileContainsJSON(path.join(tmpdir, 'packages/test/package.json.ember-try'), { originalPackageJSON: true });
+        assertFileContainsJSON(path.join(tmpdir, 'packages/test/.node_modules.ember-try/prove-it.json'), { originalNodeModules: true });
+        assertFileContainsJSON(path.join(tmpdir, 'packages/test/yarn.lock.ember-try'), { originalYarnLock: true });
+        assertFileContainsJSON(path.join(tmpdir, 'packages/test/npm-shrinkwrap.json.ember-try'), { originalNpmShrinkWrap: true });
+        assertFileContainsJSON(path.join(tmpdir, 'packages/test/package-lock.json.ember-try'), { originalPackageLock: true });
+      });
+    });
+
     it('throws an error if workspaces are not present', () => {
       writeJSONFile('package.json', {
         name: 'a-test-project-with-workspaces'
@@ -109,6 +129,41 @@ describe('workspaceAdapter', () => {
           expect(runCount).to.equal(1, 'Only yarn install should run with manager options');
         });
       });
+
+      it('uses buildManagerOptions to override defaults for yarn commands', () => {
+        let runCount = 0;
+        let stubbedRun = generateMockRun([{
+          command: 'yarn install --flat',
+          callback() {
+            runCount++;
+            return RSVP.resolve();
+          },
+        }], { allowPassthrough: false });
+
+        return new WorkspaceAdapter({
+          cwd: tmpdir,
+          run: stubbedRun,
+          useYarnCommand: true,
+          buildManagerOptions: function() {
+            return ['--flat'];
+          },
+        })._install().then(() => {
+          expect(runCount).to.equal(1, 'Only yarn install should run with buildManagerOptions');
+        });
+      });
+
+      it('throws an error if buildManagerOptions does not return an array', () => {
+        expect(() => {
+          new WorkspaceAdapter({
+            cwd: tmpdir,
+            run: () => {},
+            useYarnCommand: true,
+            buildManagerOptions: function() {
+              return 'string';
+            },
+          })._install()
+        }).to.throw(/buildManagerOptions must return an array of options/);
+      });
     });
   });
 
@@ -135,6 +190,38 @@ describe('workspaceAdapter', () => {
         assertFileContainsJSON(path.join(tmpdir, 'packages/test/node_modules/prove-it.json'), { originalNodeModules: true });
       });
     });
+
+    it('replaces the yarn.lock, npm-shrinkwrap.json and package-lock.json with the backed up version if they exist', () => {
+      fs.ensureDirSync('packages/test/node_modules');
+
+      writeJSONFile('packages/test/package.json', { originalPackageJSON: true });
+      writeJSONFile('packages/test/node_modules/prove-it.json', { originalNodeModules: true });
+      writeJSONFile('packages/test/yarn.lock', { originalYarnLock: true });
+      writeJSONFile('packages/test/npm-shrinkwrap.json', { originalNpmShrinkWrap: true });
+      writeJSONFile('packages/test/package-lock.json', { originalPackageLock: true });
+
+      let workspaceAdapter = new WorkspaceAdapter({
+        cwd: tmpdir,
+        useYarnCommand: true,
+        run: () => Promise.resolve(),
+      });
+
+      return workspaceAdapter.setup().then(() => {
+        writeJSONFile('packages/test/package.json', { originalPackageJSON: false });
+        writeJSONFile('packages/test/node_modules/prove-it.json', { originalNodeModules: true });
+        writeJSONFile('packages/test/yarn.lock', { originalYarnLock: false });
+        writeJSONFile('packages/test/npm-shrinkwrap.json', { originalNpmShrinkWrap: false });
+        writeJSONFile('packages/test/package-lock.json', { originalPackageLock: false });
+
+        return workspaceAdapter.cleanup();
+      }).then(() => {
+        assertFileContainsJSON(path.join(tmpdir, 'packages/test/package.json'), { originalPackageJSON: true });
+        assertFileContainsJSON(path.join(tmpdir, 'packages/test/node_modules/prove-it.json'), { originalNodeModules: true });
+        assertFileContainsJSON(path.join(tmpdir, 'packages/test/yarn.lock'), { originalYarnLock: true });
+        assertFileContainsJSON(path.join(tmpdir, 'packages/test/npm-shrinkwrap.json'), { originalNpmShrinkWrap: true });
+        assertFileContainsJSON(path.join(tmpdir, 'packages/test/package-lock.json'), { originalPackageLock: true });
+      });
+    });
   });
 
   describe('#changeToDependencySet', () => {
@@ -222,5 +309,30 @@ describe('workspaceAdapter', () => {
         });
       });
     });
+
+    it('passes the scenario into buildManagerOptions to run with the correct options', () => {
+      let runCount = 0;
+      workspaceAdapter.run = generateMockRun([{
+        command: 'yarn install --flat',
+        callback(command, args, opts) {
+          runCount++;
+          expect(opts).to.have.property('cwd', tmpdir);
+          return RSVP.resolve();
+        },
+      }], { allowPassthrough: false });
+      workspaceAdapter.buildManagerOptions = function(scenario) {
+        if (scenario.name === 'scenario1') {
+          return ['--flat']
+        }
+
+        return [];
+      };
+
+      return workspaceAdapter.changeToDependencySet({
+        name: 'scenario1'
+      }).then(() => {
+        expect(runCount).to.equal(1, 'yarn install should run with correct options from buildManagerOptions');
+      });
+    });
   });
 });