将 require 与相对路径一起使用
Using require with relative paths
我们对 Protractor 进行了大量的端到端测试。我们遵循页面对象模式,这有助于我们保持测试干净和模块化。我们还有一组辅助函数,可以帮助我们遵循 DRY principle.
问题:
单个规范可能需要多个页面对象和帮助程序模块。例如:
"use strict";
var helpers = require("./../../helpers/helpers.js");
var localStoragePage = require("./../../helpers/localStorage.js");
var sessionStoragePage = require("./../../helpers/sessionStorage.js");
var loginPage = require("./../../po/login.po.js");
var headerPage = require("./../../po/header.po.js");
var queuePage = require("./../../po/queue.po.js");
describe("Login functionality", function () {
beforeEach(function () {
browser.get("/#login");
localStoragePage.clear();
});
// ...
});
你可以看到我们在每个require语句中都有那个目录遍历:./../..
。这是因为我们有一个 specs
目录,我们将规范和多个目录保存在其中,这些目录按被测应用程序功能分组。
问题:
解决量角器中相对路径问题的规范方法是什么?
换句话说,我们希望避免遍历树,向上导入模块。从基本应用程序目录向下走会更干净。
尝试与思考:
有一篇关于解决这个问题的好文章:Better local require() paths for Node.js,但我不确定在使用 Protractor 开发测试时推荐使用哪个选项。
我们也尝试过使用require.main
构建路径,但是它指向node_modules/protractor
目录而不是我们的应用程序目录。
我遇到了同样的问题,最后得到了以下解决方案。
在我的 Protractor 配置文件中,我有一个变量,它存储我的 e2e 测试的基本文件夹的路径。此外,Protractor 配置提供了 onPrepare
回调,您可以在其中使用名为 global
的变量为您的测试创建全局变量。您将它们定义为该 global
变量的属性,并使用与在测试中使用全局变量 browser
或 element
相同的方式。我用它来创建自定义全局 require 函数来加载不同类型的实体:
// __dirname retuns a path of this particular config file
// assuming that protractor.conf.js is in the root of the project
var basePath = __dirname + '/test/e2e/';
// /path/to/project/test/e2e/
exports.config = {
onPrepare: function () {
// "relativePath" - path, relative to "basePath" variable
// If your entity files have suffixes - you can also keep them here
// not to mention them in test files every time
global.requirePO = function (relativePath) {
return require(basePath + 'po/' + relativePath + '.po.js');
};
global.requireHelper = function (relativePath) {
return require(basePath + 'helpers/' + relativePath + '.js');
};
}
};
然后您可以立即在测试文件中使用这些全局实用程序方法:
"use strict";
var localStorageHelper = requireHelper('localStorage');
// /path/to/project/test/e2e/helpers/localStorage.js
var loginPage = requirePO('login');
// /path/to/project/test/e2e/po/login.po.js
var productShowPage = requirePO('product/show');
// /path/to/project/test/e2e/po/product/show.po.js
describe("Login functionality", function () {
beforeEach(function () {
browser.get("/#login");
localStorageHelper.clear();
});
// ...
});
我遇到了同样的问题。与 Michael Radionov 的解决方案类似,但没有设置全局函数,而是将 属性 设置为量角器本身。
protractor.conf.js
onPrepare: function() {
protractor.basePath = __dirname;
}
测试-e2e.js
require(protractor.basePath+'/helpers.js');
describe('test', function() {
.......
});
我认为我们在工作中使用的方法对您来说可能是一个很好的解决方案。我已经发布了一个关于我们如何处理所有事情的简短示例。非常好b/c您可以在任何规范文件中调用页面对象函数,而无需在规范中使用 require。
我们一直面临同样的问题,因此决定将所有页面对象和帮助程序文件转换为节点包。现在在测试中要求它们就像 var Header = require('header-po')
一样简单。转换为包的另一个好处是您可以使用适当的版本控制。
这是一个简单的例子:
./page-objects/header-po/index.js
//page-objects/header-po/index.js
'use strict';
var Header = function () {
this.goHome = function () {
$('#logo a').click();
};
};
module.exports = Header;
./page-objects/header-po/package.json
{
"name": "header-po",
"version": "0.1.1",
"description": "Header page object",
"main": "index.js",
"dependencies": {}
}
./package.json
{
"name": "e2e-test-framework",
"version": "0.1.0",
"description": "Test framework",
"dependencies": {
"jasmine": "^2.1.1",
"header-po": "./page-objects/header-po/",
}
}
./tests/header-test.js
'use strict';
var Header = require('header-po');
var header = new Header();
describe('Header Test', function () {
it('clicking logo in header bar should open homepage', function () {
browser.get(browser.baseUrl + '/testpage');
header.goHome();
expect(browser.getCurrentUrl()).toBe(browser.baseUrl);
});
});
所有答案似乎都是变通方法
实际可行的解决方案是这样的:
- 安装module alias
- 将此添加到您的 package.json
"_moduleAliases": {
"@protractor": "protractor/_protractor",
"@tmp": "protractor/.tmp_files",
"@test_data": "protractor/.tmp_files/test_data",
"@custom_implementation": "protractor/custom_implementation",
},
- 将此添加为量角器配置的第一行
require('module-alias/register');
- 像这样在项目的任何地方使用它
const params = require('@test_data/parameters');
const customImplementation require('@custom_implementation')
// etc
我们对 Protractor 进行了大量的端到端测试。我们遵循页面对象模式,这有助于我们保持测试干净和模块化。我们还有一组辅助函数,可以帮助我们遵循 DRY principle.
问题:
单个规范可能需要多个页面对象和帮助程序模块。例如:
"use strict";
var helpers = require("./../../helpers/helpers.js");
var localStoragePage = require("./../../helpers/localStorage.js");
var sessionStoragePage = require("./../../helpers/sessionStorage.js");
var loginPage = require("./../../po/login.po.js");
var headerPage = require("./../../po/header.po.js");
var queuePage = require("./../../po/queue.po.js");
describe("Login functionality", function () {
beforeEach(function () {
browser.get("/#login");
localStoragePage.clear();
});
// ...
});
你可以看到我们在每个require语句中都有那个目录遍历:./../..
。这是因为我们有一个 specs
目录,我们将规范和多个目录保存在其中,这些目录按被测应用程序功能分组。
问题:
解决量角器中相对路径问题的规范方法是什么?
换句话说,我们希望避免遍历树,向上导入模块。从基本应用程序目录向下走会更干净。
尝试与思考:
有一篇关于解决这个问题的好文章:Better local require() paths for Node.js,但我不确定在使用 Protractor 开发测试时推荐使用哪个选项。
我们也尝试过使用require.main
构建路径,但是它指向node_modules/protractor
目录而不是我们的应用程序目录。
我遇到了同样的问题,最后得到了以下解决方案。
在我的 Protractor 配置文件中,我有一个变量,它存储我的 e2e 测试的基本文件夹的路径。此外,Protractor 配置提供了 onPrepare
回调,您可以在其中使用名为 global
的变量为您的测试创建全局变量。您将它们定义为该 global
变量的属性,并使用与在测试中使用全局变量 browser
或 element
相同的方式。我用它来创建自定义全局 require 函数来加载不同类型的实体:
// __dirname retuns a path of this particular config file
// assuming that protractor.conf.js is in the root of the project
var basePath = __dirname + '/test/e2e/';
// /path/to/project/test/e2e/
exports.config = {
onPrepare: function () {
// "relativePath" - path, relative to "basePath" variable
// If your entity files have suffixes - you can also keep them here
// not to mention them in test files every time
global.requirePO = function (relativePath) {
return require(basePath + 'po/' + relativePath + '.po.js');
};
global.requireHelper = function (relativePath) {
return require(basePath + 'helpers/' + relativePath + '.js');
};
}
};
然后您可以立即在测试文件中使用这些全局实用程序方法:
"use strict";
var localStorageHelper = requireHelper('localStorage');
// /path/to/project/test/e2e/helpers/localStorage.js
var loginPage = requirePO('login');
// /path/to/project/test/e2e/po/login.po.js
var productShowPage = requirePO('product/show');
// /path/to/project/test/e2e/po/product/show.po.js
describe("Login functionality", function () {
beforeEach(function () {
browser.get("/#login");
localStorageHelper.clear();
});
// ...
});
我遇到了同样的问题。与 Michael Radionov 的解决方案类似,但没有设置全局函数,而是将 属性 设置为量角器本身。
protractor.conf.js
onPrepare: function() {
protractor.basePath = __dirname;
}
测试-e2e.js
require(protractor.basePath+'/helpers.js');
describe('test', function() {
.......
});
我认为我们在工作中使用的方法对您来说可能是一个很好的解决方案。我已经发布了一个关于我们如何处理所有事情的简短示例。非常好b/c您可以在任何规范文件中调用页面对象函数,而无需在规范中使用 require。
我们一直面临同样的问题,因此决定将所有页面对象和帮助程序文件转换为节点包。现在在测试中要求它们就像 var Header = require('header-po')
一样简单。转换为包的另一个好处是您可以使用适当的版本控制。
这是一个简单的例子:
./page-objects/header-po/index.js
//page-objects/header-po/index.js
'use strict';
var Header = function () {
this.goHome = function () {
$('#logo a').click();
};
};
module.exports = Header;
./page-objects/header-po/package.json
{
"name": "header-po",
"version": "0.1.1",
"description": "Header page object",
"main": "index.js",
"dependencies": {}
}
./package.json
{
"name": "e2e-test-framework",
"version": "0.1.0",
"description": "Test framework",
"dependencies": {
"jasmine": "^2.1.1",
"header-po": "./page-objects/header-po/",
}
}
./tests/header-test.js
'use strict';
var Header = require('header-po');
var header = new Header();
describe('Header Test', function () {
it('clicking logo in header bar should open homepage', function () {
browser.get(browser.baseUrl + '/testpage');
header.goHome();
expect(browser.getCurrentUrl()).toBe(browser.baseUrl);
});
});
所有答案似乎都是变通方法
实际可行的解决方案是这样的:
- 安装module alias
- 将此添加到您的 package.json
"_moduleAliases": {
"@protractor": "protractor/_protractor",
"@tmp": "protractor/.tmp_files",
"@test_data": "protractor/.tmp_files/test_data",
"@custom_implementation": "protractor/custom_implementation",
},
- 将此添加为量角器配置的第一行
require('module-alias/register');
- 像这样在项目的任何地方使用它
const params = require('@test_data/parameters');
const customImplementation require('@custom_implementation')
// etc