TestCafe config setup for multiple environments - testing

I'm wondering if it's possible to have a single .testcaferc.json file that provides config for all environments?
We've got a lot of config that's shared, so I don't really want to create individual config files for each environment if I don't have to.
Something like this would be great, but can't seem to see anything in the tc docs that mentions anything about environments
{
browsers: "chrome",
concurrency: 5,
baseUrl: "http://localhost:3000",
...
env: {
dev: {
baseUrl: "https://dev.example.com",
...
},
test: {
baseUrl: "https://test.example.com",
...
},
prod: {
baseUrl: "https://example.com",
...
},
}
}
Currently we pass a number of extra args into the scripts as below, which is getting really messy and difficult to maintain in our package file.
{
"test:e2e": "npm run test:cafe",
"test:e2e:dev": "npm run test:cafe -- --base-url=https://dev.example.com",
"test:e2e:test": "npm run test:cafe -- --base-url=https://test.example.com",
"test:e2e:prod": "npm run test:cafe -- --base-url=https://example.com","
}
Thanks!

You can use the JavaScript config file instead of a JSON config file. In this case, you can write your own logic right inside the config. For example, you can check the environment variable as follows:
.testcaferc.js:
module.exports = {
baseUrl: process.env.dev ? 'http://localhost:3000' : 'http://localhost:3005',
customActions: {},
}
Moreover, you can create different configuration files for different environments, and one for common settings. In this case, you can use the common settings from the common config file and import specific environment settings from other config files.
Common: .testcaferc.js
function resolveEnv () {
if (process.env.dev)
return './.testcaferc-dev.js'
else if (process.env.test)
return './.testcaferc-test.js'
else
return './.testcaferc-prod.js'
}
const commonConfig = {
skipJsErrors: true,
customActions: {}
}
const envConfigName = resolveEnv();
const envConfig = require(envConfigName);
module.exports = {
...commonConfig,
...envConfig,
}
.testcaferc-dev.js
module.exports = {
baseUrl: 'http://localhost:3000',
skipJsErrors: false,
}

Related

Cypress 12 Component Tests Wont Load

I am trying to use Cypress 12 to run compnent tests in a Vue.js 2 app. Below is my cypress.config.ts file:
import { defineConfig } from "cypress";
export default defineConfig({
e2e: {
setupNodeEvents(on, config) {
// implement node event listeners here
},
baseUrl: "http://localhost:9090/.......",
defaultCommandTimeout: 60000,
},
component: {
devServer(cypressConfig: CypressConfiguration) {
// return devServer instance or a promise that resolves to
// a dev server here
return {
port: 9090,
close: () => {},
};
},
},
});
I setup a custom devServer in vue.config.js (otherwise Cypress starts uses its own localhost):
module.exports = {
devServer: {
port: 9090,
proxy: 'http://localhost:8080'
}
}
However, the tests wont load
When I run e2e tests, all is fine: tests appears, calls localhost:9090. However, if I want to run only component tests, it just gets stuck trying to load the tests.
It is not a DevTools problem as I have looked into that. All other configuration settings are standard.

Avoid browser caching after deploy a Vuejs app

My Vuejs App did not update after deployment for production, every time require "Empty cache and hard reload" to get the updates, I tried a lot of solutions to apply versioning to generated files after build but none of them worked for me, I need a solution to apply new hash for all files after every single build, not just the updated ones.
My vue.config.js file content:
const path = require("path");
module.exports = {
publicPath: process.env.NODE_ENV === "production" ? "/" : "/",
runtimeCompiler: true,
configureWebpack: {
resolve: {
alias: {
// If using the runtime only build
// vue$: "vue/dist/vue.runtime.esm.js" // 'vue/dist/vue.runtime.common.js' for webpack 1
// Or if using full build of Vue (runtime + compiler)
vue$: 'vue/dist/vue.esm.js', // 'vue/dist/vue.common.js' for webpack 1
'#': path.resolve('src'),
src: path.resolve('src'),
assets: path.resolve('src/assets'),
components: path.resolve('src/components'),
services: path.resolve('src/services'),
}
},
output: {
filename: '[name].[hash].js',
},
},
chainWebpack: config => {
config.module
.rule("eslint")
.use("eslint-loader")
.tap(options => {
options.configFile = path.resolve(__dirname, ".eslintrc.js");
return options;
});
},
};
Thanks in advance.
Welcome to the Vue JS cache nightmare. Did you try changing the version value in your package.json? I use to increment the value on each release as per x.y.z semantinc versioning. Maybe doing something like this:
{
"name": "My app",
"version": "1.0.15",
"private": true,
...
}

Serving a modified asset-manifest.json in CRA using CRACO doesn't work

I have just created a new CRA app. In our organization we have a micro frontend framework which has certain requirements when it comes to the the asset file of each micro frontend app. CRA will by default, create a asset-manifest.json file.
https://github.com/facebook/create-react-app/blob/main/packages/react-scripts/config/webpack.config.js#L656
Now I need to change this file to assets.json and make some structural changes as well. To achieve this I use CRACO and add the WebpackManifestPlugin.
const ManifestPlugin = require('webpack-manifest-plugin');
module.exports = {
webpack: {
plugins: {
// tried removing CRA definition for ManifestPlugin.
// It worked, but had no impact on my problem
// remove: ['ManifestPlugin'],
add: [
new ManifestPlugin({
fileName: 'assets.json',
generate: (seed, files, entrypoints) => {
const js = [],
css = [];
files.forEach((file) => {
if (file.path.endsWith('.js') && file.isInitial) {
js.push({ value: file.path, type: 'entry' });
}
if (file.path.endsWith('.css') && file.isInitial) {
css.push({ value: file.path, type: 'entry' });
}
});
return { js, css };
},
})
]
}
}
};
Whenever I build the application, my new assets.json file is generated as expected.
However, I can't get CRA, or webpack-dev-server I assume, to serve this file while I run my CRA app in development mode. It only resolves to the index.html file. I have looked through CRA source code and can't really find any relevant place where asset-manifest.json is mentioned.
So how do I get webpack-dev-server to serve my assets.json file?
You need to add the ManifestPlugin to webpack.plugins.remove array to receive only the configuration from WebpackManifestPlugin:
...
webpack: {
alias: {},
plugins: {
add: [
new WebpackManifestPlugin(webpackManifestConfig)
],
remove: [
"ManifestPlugin"
],
},
configure: (webpackConfig, { env, paths }) => { return webpackConfig; }
},
...

Setup of vue.config.js file to imitate production setup (connect two apps)

I run an R Shiny app on port 3000 which serves my vue.js App like this:
library(shiny)
server <- function(input, output, session) {
histogramData <- reactive({
mtcars
})
observe({
session$sendCustomMessage("histogramData", histogramData())
})
}
ui <- function() {
htmlTemplate("dist/index.html")
}
# Serve the bundle at js/main.js
if (dir.exists("dist/js")) {
addResourcePath("js", "dist/js")
}
# Serve the bundle at js/main.js
if (dir.exists("dist/css")) {
addResourcePath("css", "dist/css")
}
# Serve the bundle at js/main.js
if (dir.exists("dist/img")) {
addResourcePath("img", "dist/img")
}
shinyApp(ui, server)
For development, I would change it like this:
ui <- function() {
htmlTemplate("public/index.html")
}
However, I can not always run the build process just to connect the apps, I want to use the dev server to connect the apps and send data back and forth.
I have setup a vue.config.js with the following configuration to create a connection between the two apps.
const path = require('path')
module.exports = {
publicPath: ".",
devServer: {
port: 4000,
contentBase: path.resolve(__dirname, 'public'),
proxy: {
'/': {
target: 'http://localhost:3000'
},
'/websocket': {
target: 'ws://localhost:3000',
ws: true
}
}
},
transpileDependencies: [
"vuetify"
]
}
This was taken from a github repository, I am acutally quite clueless how to archieve this connection. My idea was to connect go on localhost:4000 and receive the data from localhost:3000, but nothing gets passed:
TypeError: Cannot read property 'addCustomMessageHandler' of undefined at VueComponent.mounted (HelloWorld.vue?140d:42)
This is based on the following method in my vue component (which works perfectly after the build process):
mounted: function () {
window.Shiny.addCustomMessageHandler('histogramData', histogramData =>
this.data.histogramData = histogramData
)
Can anyone tell me what´s wrong and help me to setup the connection correctly?

How to keep my keys in safe in react native (expo)?

I have 3 release channels - dev, qa, prod.
const ENV_MODES = {
dev: {
},
prod: {
},
qa: {
}
}
ENV_MODES.default = ENV_MODES.prod
const getEnvVars = channel => {
if (process.env.NODE_ENV !== 'production') return ENV_MODES.dev
if (channel === null || channel === undefined || channel === '') return ENV_MODES.prod
if (channel.startsWith(ENV_DEV)) return ENV_MODES.dev
if (channel.startsWith(ENV_QA)) return ENV_MODES.qa
if (channel.startsWith(ENV_PROD)) return ENV_MODES.prod
return ENV_MODES.default
}
const ENV = getEnvVars(Constants.manifest.releaseChannel)
But I don't want to put keys into the repo.
How should I handle this? As I understand I can't expect that I will have NODE_ENV === 'qa' when I will publish in QA channel
You could use react-native-dotenv and add your keys to a .env file and add it to .gitignore. This way you won't be pushing keys to your repo and you can change your variables depending on the environment your code is running on.
To use the lib you only need to add it to your devDependencies and add it to you babel.config.js file, like so:
module.exports = function (api) {
api.cache(true);
return {
presets: [
'babel-preset-expo',
'module:react-native-dotenv',
],
};
};
EDIT:
NODE_ENV won't be the same as your release channel. If you want to load configs based on the release channel use Expo.Constants.manifest.releaseChannel.
However have in mind this variable doesn't exist in Dev mode, as per expo's docs.
Expo.Constants.manifest.releaseChannel does NOT exist in dev mode. It does exist, however when you explicitly publish / build with it.
EDIT 2:
Here's an example on how you can achieve both individual configurations for each release channel and use react-native-dotenv to avoid pushing secrets to your Git repo (since this is a big no no).
Remember: add your .env file to your .gitignore.
Constants.js
// eslint-disable-next-line import/no-extraneous-dependencies
import { AWS_KEY } from 'react-native-dotenv';
import { Constants as ExpoConstants } from 'expo';
const getChannelConfigs = (releaseChannel = '') => {
switch (releaseChannel) {
case 'qa':
return {
API_URL: 'https://qa.com/api',
...
};
case 'prod':
return {
API_URL: 'https://prod.com/api/',
...
};
default:
return {
API_URL: 'https://dev.com/api/',
...
};
}
};
const CHANNEL_CONFIGS = Object.freeze(getChannelConfigs(ExpoConstants.manifest.releaseChannel));
export default { AWS_KEY, CHANNEL_CONFIGS };
.env
AWS_KEY='superSecretKeyDoNOTStealThx'
In this example we are configuring which API URL the app will call based on its release channel. We're also avoiding commiting keys to our Git repo, since we now have them in a cozy .env file.
It's also worth mentioning this setup works when building a standalone app in your CI, but handing secret keys to your users might not be the best idea.
Expo now has eas.json file that sits in root of your app. That file can define all the build profiles and variables if needed. The submit feature of the configuration helps manage all the app store related configs.
Sensitive secrets (prod ids and paths) , feature flags are all possible to configure.
https://docs.expo.dev/build-reference/variables/
{
"build": {
"production": {
"node": "16.13.0",
"env": {
"API_URL": "https://company.com/api"
}
},
"preview": {
"extends": "production",
"distribution": "internal",
"env": {
"API_URL": "https://staging.company.com/api"
}
}
}
"submit": {
"production": {
"android": {
"serviceAccountKeyPath": "../path/to/api-xxx-yyy-zzz.json",
"track": "internal"
},
"ios": {
"appleId": "john#turtle.com",
"ascAppId": "1234567890",
"appleTeamId": "AB12XYZ34S"
}
}
}
}