Managing multi sites in cypress - javascript

Following are the three country based sites I am having -
Site 1 - https://example.com/uk
Site 2 - https://example.com/fr
Site 3 - https://example.com/ie
All 3 sites are using same code base and on the basis of country (uk | fr | ie) in my code I am passing some default configuration, like country specific text and some feature enable/disable switch etc. to the inner pages.
In my cypress, I have created fixtures like -
/fixtures -
/uk
-uk-config.json
/fr
-fr-config.json
/ie
-ie-config.json
I am stuck with the folder structure in integration folder and do not know the recommended way of doing this. Please help me on this.
Option 1-
/integration -
/uk
-homepage.spec.js
-plp.spec.js
-pdp.spec.js
-cart.spec.js
/fr
-homepage.spec.js
-plp.spec.js
-pdp.spec.js
-cart.spec.js
/ie
-homepage.spec.js
-plp.spec.js
-pdp.spec.js
-cart.spec.js
Problem with this approach - Though this code is more segregated on country basis, but here lot of code duplicates and it get increases as we launch other country stores.
Option 2 -
/integration -
-homepage.spec.js
-plp.spec.js
-pdp.spec.js
-cart.spec.js
And in this pass, country specific configurations from fixtures. TBH, I don't know how can I manage this and it would really be good if someone find this is a better way and can provide some pointers toward this would really be helpful.

Problem:If I understood your problem clearly, you want to run your same set of tests but for different countries and you are facing issues in reading and there is a problem that suite gets increased if too many countries will be added just to test same set of tests. Right ??
Solution:
You can pass the COUNTRY variable as node env variable from command line and assign that as Cypress env variable and read it in your tests.
"test": "COUNTRY=$COUNTRY ./node_modules/.bin/cypress open --env COUNTRY=$COUNTRY"
Your run command should be like below
COUNTRY=fr npm run test
COUNTRY=in npm run test
COUNTRY=uk npm run test
COUNTRY=whatever npm run test
let json = require('config.json');
export const getCountryUrl = () => {
return json[Cypress.env().COUNTRY]['url']
}
{
"uk": {
"url": "https://uk-website"
},
"fr": {
"url": "https://fr-website"
}
}

Related

Change .page URL based on environment I need to run the suite in

We have been building our automation suite using our staging environment, but are going live soon and want to be ready to tell the project where to run (staging, production).
The only difference between the sites in the environments is the URL. My question is, from start to finish, how can I set the .page URL via a CLI option?
Right now, I have created an environment config file that holds our staging and production URLS and then I call the data into my test files. This is fine for now, but I will need to create a script with an option to set the environment at runtime without having to do a manual find and replace before kicking it off.
I've looked around online and find, what I believe, to be code snippets and general instructions, but I'm not a dev at heart and go crossed eyed. If I could get an ELI5 for this, that would be awesome.
Example of what I'm doing now:
const env = require('../environment_variables.json')
fixture `blog`
.page `${env.production}`
And then I change production to staging or vice versa manually before kicking off the suite.
Since the project will run from CICD, I would like to be able to do something like this in my CLI and script:
testcafe env=production
The env value will then be set where the .page call is for every test file.
Thanks!
There are different ways of doing this. I've used environment variables successfully in this situation, so I'll share this solution since it will solve your problem.
I create config.json in the root of the project:
{
"baseUrl": {
"dev": "https://dev.com/",
"staging": "https://staging.com/",
"prod": "https://prod.com/"
}
}
Then I create two helper functions somewhere like Helpers/env.js:
import config from '../config';
function getEnv () {
return process.env.TESTCAFE_ENV;
}
function getBaseUrl () {
return config.baseUrl[getEnv()];
}
export { getEnv, getBaseUrl };
Then in my test files in Tests/:
import { getBaseUrl } from '../Helpers/env';
const baseUrl = getBaseUrl();
fixture `Test Suite`
.page(baseUrl);
And that's it. Then when I need to run tests on the dev, I execute:
$ TESTCAFE_ENV=dev testcafe
for staging:
$ TESTCAFE_ENV=staging testcafe
and for production:
$ TESTCAFE_ENV=prod testcafe
In v1.20.0 and later, TestCafe offers a way to specify the baseUrl in the test run configuration. You can use this approach along with environment variables, see the following example:
.testcaferc.js
const BASE_URL_MAP = {
dev: 'https://dev.com/',
staging: 'https://staging.com/',
prod: 'https://prod.com/'
};
module.exports = {
baseUrl: BASE_URL_MAP[process.env.TESTCAFE_ENV]
};
Alternatively, you can use different configuration files for each of the required setups using the --config-file option.

Usage of Bazel to build polyglot projects

I have a Kotlin JVM project that runs some JavaScript in an native runtime. Currently, the different language sources are defined in separate repositories and the JS file is webpacked and packaged as a JAR to be specified as a dependency of the JVM project. This works fine, but I want to merge the two repositories as they are inherently coupled. Rather than maintain an abundance of different build tooling, I thought it would be a good opportunity to learn and use a polyglot build system, like Bazel.
The current structure:
Essentially, there are two main packages I'm trying to build. The web package builds correctly and I can view the webpacked output via command line. Including the web BUILD file for full picture:
load("#npm_bazel_typescript//:index.bzl", "ts_library")
ts_library(
name = "compileCore",
srcs = ["index.ts"],
tsconfig = "tsconfig.json",
)
filegroup(
name = "internalCore",
srcs = ["compileCore"],
output_group = "es5_sources",
)
load("#npm//webpack-cli:index.bzl", webpack = "webpack_cli")
webpack(
name = "bundle",
outs = ["bundle.prod.js"],
args = [
"--mode production",
"$(execpath internalCore)",
"--config",
"$(execpath webpack.config.js)",
"-o",
"$#",
],
data = [
"internalCore",
"webpack.config.js",
"#npm//:node_modules",
],
visibility = ["//visibility:public"],
)
The other important package is the nested //jvm/src/main/java/com/example/bazel/plugin package. This is essentially the final deliverable, which should be a JAR with the output of the web package included as resources.
load("#io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kt_jvm_library")
kt_jvm_library(
name = "plugin",
srcs = glob(["*.kt"]),
deps = [
# ... some deps
],
resources = ["//web:bundle"],
visibility = ["//visibility:public"],
)
This is seemingly straightforward, but errors during the build with:
❯ bazel build //jvm/src/...
INFO: Analyzed target //jvm/src/main/java/com/example/bazel/plugin:plugin (0 packages loaded, 0 targets configured).
INFO: Found 1 target...
ERROR: /Users/jzucker/dev/GitHub/plugin-example-bazel/jvm/src/main/java/com/example/bazel/plugin/BUILD:12:15: error executing shell command: '/bin/bash -c external/bazel_tools/tools/zip/zipper/zipper c bazel-out/darwin-fastbuild/bin/jvm/src/main/java/com/example/bazel/plugin/plugin-resources.jar #bazel-out/darwin-fastbuild/bin/jvm/src/ma...' failed (Exit 255) bash failed: error executing command /bin/bash -c ... (remaining 1 argument(s) skipped)
Use --sandbox_debug to see verbose messages from the sandbox
File web/bundle.prod.js does not seem to exist.Target //jvm/src/main/java/com/example/bazel/plugin:plugin failed to build
Use --verbose_failures to see the command lines of failed build steps.
INFO: Elapsed time: 0.402s, Critical Path: 0.05s
INFO: 0 processes.
FAILED: Build did NOT complete successfully
After some experimentation, this seems to be an issue of trying to bundle generated outputs as resources for a kt_jvm_library. If the resources reference a tangible source file from another package, then it works just fine. The main question here is whether this is the right pattern for Bazel or if I'm trying to abuse this technology. This seems like a relatively simple use case, but there is a line in the docs that concerns me the most:
An invariant of all rules is that the files generated by a rule always belong to the same package as the rule itself; it is not possible to generate files into another package. It is not uncommon for a rule's inputs to come from another package, though.
From https://docs.bazel.build/versions/master/build-ref.html
Any insight would be greatly appreciated.
This is actually a bug in the Bazel Kotlin ruleset:
github.com/bazelbuild/rules_kotlin/issues/281
Until that is fixed, you can package the resources in a java_library and include that as resource_jars.
java_library(
name = "resources",
resources = ["//web:bundle"],
resource_strip_prefix = "web",
)
load("#io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kt_jvm_library")
kt_jvm_library(
name = "plugin",
srcs = glob(["*.kt"]),
deps = [
# ... some deps
],
resource_jars = ["resources"],
visibility = ["//visibility:public"],
)

Change environment in the test instead of command line arg

I want to be able to change the environment of a test in the code instead of the command line, example:
http://nightwatchjs.org/gettingstarted#test-settings
nightwatch --env xpto will change to the environment in the config of the nighwatch called xpto.
I want to do that in the test,
For example...
export default {
before : function (client) {
//This is just for explanation.
client.options.setEnvironment("xpto");
},
...
...
There is some kind of function or something to do this?
My case scenario is...
I have a docker image to run the tests and i want to have one environment without user agent and another one with it in the same command...
Then i should just have 2 testsFiles one using the default environment and the other one using the xptoenvironment.
Thanks in advance!

Getting the spec file name into TAP file

we use testem to run our javascript unit tests. As output I get a TAP file, that looks similar like this
ok 1 PhantomJS 2.1 - ABC Directive should contain a template
---
Log: |
{ type: 'log',
text: '\'WARNING: Tried to load angular more than once.\'\n' }
...
lets say, the test is defined ABCItemSpec.coffee. Is there anyway to include this file name in the final TAP output ?
I do not understand much about the javascript/gulp setup her, so the question might be too blurry, but maybe there is a general solution (the way to setup testem, or to give the spec file as argument etc) ?

Pull an HTML file into a TinyTest

TinyTest seems to be concerned only with unit testing; however, may Meteor packages have UI elements, and it would be helpful to pull in a pre-crafted HTML file that exercises a widget. For instance, we might want to transform a <table> into a grid with DataTables.net, then test if the instantiation was correct.
How can external HTML files be used in a TinyTest?
package.js:
Package.onTest(function (api) {
api.use(packageName, where);
api.use(['tinytest', 'http'], where);
// TODO we should just bring in src/test.html - but how to do that with TinyTest?
api.addFiles('src/test.html', where); // this won't magically display the HTML anywhere
api.addFiles('meteor/test.js', where);
});
test.js:
Tinytest.addAsync('Visual check', function (test, done) {
var iconsDropZone = document.createElement('div');
document.body.appendChild(iconsDropZone);
// TODO ideally we'd get src/test.html straight from this repo, but no idea how to do this from TinyTest
HTTP.get('https://rawgit.com/FortAwesome/Font-Awesome/master/src/test.html', function callback(error, result) {
if (error) {
test.fail('Error getting the icons. Do we have an Internet connection to rawgit.com?');
} else {
iconsDropZone.innerHTML = result.content;
test.ok({message: 'Test passed if the icons look OK.'});
}
done();
});
});
I personally think TinyTest is not the right tool for the job! You may get away with finding out how to include the Asset package or writing your own file loader, but you'll soon face the problem of needing to query the DOM in your tests.
Here are some options I can think of:
Option 1:
You can get access to a fully rendered page by using xolvio:webdriver. If you include this package in your onTest block, then you should have access to wdio in your TinyTest tests. I say should as I don't use TinyTest at all but I designed the webdriver package to be usable by any framework. Follow the instructions on the package readme and then do something like this:
browser.
init().
url('https://rawgit.com/FortAwesome/Font-Awesome/master/src/test.html').
getSource(function(err, source) {
// you have a fully rendered source here and can compare to what you like
}).
end();
It's a heavyweight option but might be suitable for you.
Option 2:
If you're willing to move away from TinyTest, another option is to use Jasmine. It supports client unit testing so you can load up the unit that does the visuals and isolate it with a unit test.
Option 3:
You can create a test app around your package. So you would have:
/package
/package/src
/package/example
/package/example/main.html
/package/example/tests
/package/example/tests/driver.js
And now the example directory is a Meteor app. In main.html you would use your package and under tests directory you can use the framework of your choice (jasmine/mocha/cucumber) in combination with webdriver. I like this pattern for package development as you can test the package as it is intended to be used by apps.

Categories