From 437b9b584c162be2bf41d209de55e35b8b1555d5 Mon Sep 17 00:00:00 2001 From: Gleb Bahmutov Date: Thu, 1 Jun 2017 11:28:34 -0400 Subject: [PATCH 1/3] server: save bundles separately per project, close #116 --- packages/server/lib/log.coffee | 4 ++++ packages/server/lib/util/bundle.coffee | 7 +++++-- packages/server/lib/util/saved_state.coffee | 9 +++++---- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/packages/server/lib/log.coffee b/packages/server/lib/log.coffee index 222081a218..4f0f89bd25 100644 --- a/packages/server/lib/log.coffee +++ b/packages/server/lib/log.coffee @@ -6,4 +6,8 @@ # use # log = require('./log') # log('working in %s', process.cwd()) +# If you need a logger that might be very specific +# you can construct it yourself, just make sure +# to prefix label with "cypress:server:", for example +# log = require('debug')('cypress:server:bundle') module.exports = require('debug')('cypress:server') diff --git a/packages/server/lib/util/bundle.coffee b/packages/server/lib/util/bundle.coffee index 31d3811417..76bce59584 100644 --- a/packages/server/lib/util/bundle.coffee +++ b/packages/server/lib/util/bundle.coffee @@ -11,9 +11,10 @@ presetReact = require("babel-preset-react") presetLatest = require("babel-preset-latest") stringStream = require("string-to-stream") pluginAddModuleExports = require("babel-plugin-add-module-exports") -sanitize = require("sanitize-filename") cjsxify = require("./cjsxify") appData = require("./app_data") +{ toHashName } = require('./saved_state') +log = require('debug')('cypress:server:bundle') fs = Promise.promisifyAll(fs) @@ -25,7 +26,7 @@ module.exports = { builtFiles = {} outputPath: (projectName = "", filePath) -> - appData.path("bundles", sanitize(projectName), filePath) + appData.path(toHashName(projectName), "bundles", filePath) build: (filePath, config) -> if config.isHeadless and built = builtFiles[filePath] @@ -59,6 +60,8 @@ module.exports = { bundle = => new Promise (resolve, reject) => outputPath = @outputPath(config.projectName, filePath) + log "making bundle to #{outputPath}" + ## TODO: only ensure directory when first run and not on updates? fs.ensureDirAsync(path.dirname(outputPath)) .then => diff --git a/packages/server/lib/util/saved_state.coffee b/packages/server/lib/util/saved_state.coffee index 663a66020f..900323a211 100644 --- a/packages/server/lib/util/saved_state.coffee +++ b/packages/server/lib/util/saved_state.coffee @@ -1,11 +1,12 @@ log = require('../log') fs = require('fs') -path = require('path') +{ basename, join } = require('path') md5 = require('md5') +sanitize = require("sanitize-filename") toHashName = (projectPath) -> throw new Error("Missing project path") unless projectPath - name = path.basename(projectPath) + name = sanitize(basename(projectPath)) hash = md5(projectPath) "#{name}-#{hash}" @@ -15,14 +16,14 @@ formStatePath = (projectPath) -> log('for project path %s', projectPath) else log('missing project path, looking for project here') - cypressJsonPath = path.join(process.cwd(), 'cypress.json') + cypressJsonPath = join(process.cwd(), 'cypress.json') if fs.existsSync(cypressJsonPath) log('found cypress file %s', cypressJsonPath) projectPath = process.cwd() statePath = "state.json" if projectPath - statePath = path.join(toHashName(projectPath), statePath) + statePath = join(toHashName(projectPath), statePath) return statePath From 92f0cae3492fc197d664aa6907257e09305f6b79 Mon Sep 17 00:00:00 2001 From: Gleb Bahmutov Date: Thu, 1 Jun 2017 13:33:27 -0400 Subject: [PATCH 2/3] bundles are saved and served from subfolders --- .gitignore | 1 + packages/server/lib/controllers/spec.coffee | 3 ++- packages/server/lib/util/bundle.coffee | 12 +++++++----- packages/server/lib/util/saved_state.coffee | 4 +++- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index 0c89e2c191..ec7bcdde72 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ node_modules *.orig dist dist-* +.vscode diff --git a/packages/server/lib/controllers/spec.coffee b/packages/server/lib/controllers/spec.coffee index 550659629f..384ff23fa3 100644 --- a/packages/server/lib/controllers/spec.coffee +++ b/packages/server/lib/controllers/spec.coffee @@ -14,7 +14,8 @@ module.exports = { res.type("js") streamBundle = -> - fs.createReadStream(bundle.outputPath(config.projectName, spec)) + bundledPath = bundle.outputPath(config.projectRoot, spec) + fs.createReadStream(bundledPath) .pipe(res) if config.isHeadless diff --git a/packages/server/lib/util/bundle.coffee b/packages/server/lib/util/bundle.coffee index 76bce59584..5eec87f005 100644 --- a/packages/server/lib/util/bundle.coffee +++ b/packages/server/lib/util/bundle.coffee @@ -25,16 +25,19 @@ module.exports = { reset: -> builtFiles = {} - outputPath: (projectName = "", filePath) -> - appData.path(toHashName(projectName), "bundles", filePath) + outputPath: (projectRoot = "", filePath) -> + appData.path(toHashName(projectRoot), "bundles", filePath) build: (filePath, config) -> if config.isHeadless and built = builtFiles[filePath] return built + log "bundler for project #{config.projectRoot}" + emitter = new EE() absolutePath = path.join(config.projectRoot, filePath) + log "input absolute path #{absolutePath}" bundler = browserify({ entries: [absolutePath] @@ -59,9 +62,8 @@ module.exports = { bundle = => new Promise (resolve, reject) => - outputPath = @outputPath(config.projectName, filePath) - log "making bundle to #{outputPath}" - + outputPath = @outputPath(config.projectRoot, filePath) + log "making bundle #{outputPath}" ## TODO: only ensure directory when first run and not on updates? fs.ensureDirAsync(path.dirname(outputPath)) .then => diff --git a/packages/server/lib/util/saved_state.coffee b/packages/server/lib/util/saved_state.coffee index 900323a211..31dd367a41 100644 --- a/packages/server/lib/util/saved_state.coffee +++ b/packages/server/lib/util/saved_state.coffee @@ -1,11 +1,12 @@ log = require('../log') fs = require('fs') -{ basename, join } = require('path') +{ basename, join, isAbsolute } = require('path') md5 = require('md5') sanitize = require("sanitize-filename") toHashName = (projectPath) -> throw new Error("Missing project path") unless projectPath + throw new Error("Expected project absolute path, not just a name #{projectPath}") unless isAbsolute(projectPath) name = sanitize(basename(projectPath)) hash = md5(projectPath) "#{name}-#{hash}" @@ -23,6 +24,7 @@ formStatePath = (projectPath) -> statePath = "state.json" if projectPath + log "state path for project #{projectPath}" statePath = join(toHashName(projectPath), statePath) return statePath From 8a659456caa35c5b9d69c80fabeaf5a45649cc72 Mon Sep 17 00:00:00 2001 From: Gleb Bahmutov Date: Thu, 1 Jun 2017 13:59:11 -0400 Subject: [PATCH 3/3] fix spec serving unit test --- .../server/test/unit/saved_state_spec.coffee | 8 +++---- packages/server/test/unit/spec_spec.coffee | 24 +++++++++++-------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/packages/server/test/unit/saved_state_spec.coffee b/packages/server/test/unit/saved_state_spec.coffee index 02530a69f2..b3536791f9 100644 --- a/packages/server/test/unit/saved_state_spec.coffee +++ b/packages/server/test/unit/saved_state_spec.coffee @@ -44,11 +44,11 @@ describe "lib/saved_state", -> expect(statePath).to.equal(expected) it "caches state file instance per path", -> - a = savedState("foo/bar") - b = savedState("foo/bar") + a = savedState("/foo/bar") + b = savedState("/foo/bar") expect(a).to.equal(b) it "returns different state file for different path", -> - a = savedState("foo/bar") - b = savedState("foo/baz") + a = savedState("/foo/bar") + b = savedState("/foo/baz") expect(a).to.not.equal(b) diff --git a/packages/server/test/unit/spec_spec.coffee b/packages/server/test/unit/spec_spec.coffee index 79ad057ed9..10c6ac2021 100644 --- a/packages/server/test/unit/spec_spec.coffee +++ b/packages/server/test/unit/spec_spec.coffee @@ -43,10 +43,13 @@ browserifyFile = (filePath) -> ) describe "lib/controllers/spec", -> + specName = "sample.js" + specSource = ";" + beforeEach -> @config = { projectName: "foo?bar" - projectRoot: "" + projectRoot: "/foobar" integrationFolder: fixturesRoot browserify: { basedir: fixturesRoot @@ -67,14 +70,15 @@ describe "lib/controllers/spec", -> watchBundle: -> Promise.resolve() } - fs.ensureDirSync(appData.path("bundles", "foobar")) - fs.writeFileSync(appData.path("bundles", "foobar", "sample.js"), ';') + samplePath = bundle.outputPath(@config.projectRoot, specName) + fs.ensureDirSync(path.dirname(samplePath)) + fs.writeFileSync(samplePath, ';') @handle = (filePath) => spec.handle filePath, {}, @res, @config, (=>), @watchers, @project it "sets the correct content type", -> - @handle("sample.js") + @handle(specName) expect(@res.type) .to.have.been.calledOnce @@ -83,15 +87,15 @@ describe "lib/controllers/spec", -> describe "headed mode", -> it "sends the file from the bundles path", -> - @handle("sample.js") + @handle(specName) collectResponse(@res).then (result) -> - expect(result).to.equal(";") + expect(result).to.equal(specSource) it "sends the client-side error if there is one", -> @watchers.watchBundle = -> Promise.reject(new Error("Reason request failed")) - @handle("sample.js").then => + @handle(specName).then => expect(@res.send).to.have.been.called expect(@res.send.firstCall.args[0]).to.include("(function") expect(@res.send.firstCall.args[0]).to.include("Reason request failed") @@ -104,10 +108,10 @@ describe "lib/controllers/spec", -> @config.isHeadless = true it "sends the file from the bundles path", -> - @handle("sample.js") + @handle(specName) collectResponse(@res).then (result) -> - expect(result).to.equal(";") + expect(result).to.equal(specSource) it "logs the error and exits if there is one", -> err = new Error("Reason request failed") @@ -117,7 +121,7 @@ describe "lib/controllers/spec", -> }) @log = @sandbox.stub(errors, "log") - @handle("sample.js").then => + @handle(specName).then => expect(@log).to.have.been.called expect(@log.firstCall.args[0].stack).to.include("Oops...we found an error preparing this test file") expect(@project.emit).to.have.been.calledWithMatch("exitEarlyWithErr", "Oops...we found an error preparing this test file")