How to run the same e2e tests on different enviroments in playwright - e2e-testing

I have a set of e2e tests.
We have a test enviroment: test.mypage.com
And we also have a UAT enviroment: uat.mypage.com
I want to be able to run the same e2e tests on either our test or uat enviroment, depending on the command line i use.
my config file:
import { LaunchOptions } from 'playwright';
const browserOptions: LaunchOptions = {
headless: false,
slowMo: 0,
args: []
};
export const config = {
browserOptions,
env: {
server: 'test'
}
};
my step file:
Given(/^i go to login page$/, async function () {
await PW.page.goto(`https://${config.env.server}.mypage.com/`);
});
the command line I use to run my tests:
npx cucumber-js
So I assume the solution would be something like
npx cucumber-js --server "uat"
but either my syntax is wrong or I'm missing something. When I run the script above, I get an error: unknown option: '--server'.
I tried
npx cucumber-js `$env:server="uat"
which didn't throw any errors but the environment remained test.mypage.com.
So how can I change the environment from the command line?

You can use the baseurl test option for this.
In your config file, add the baseurl:
import { PlaywrightTestConfig } from '#playwright/test';
const config: PlaywrightTestConfig = {
use: {
baseURL: `https://${config.env.server}.mypage.com/`,
},
};
export default config;
So now your test should look like this:
Given(/^i go to login page$/, async function () {
await PW.page.goto('/');
});
Now from CLI, you can run with a different baseurl like this:
URL=https://playwright.dev npx playwright test

Related

Serverless Cannot Run Simple Example Query Using Node.JS

I am trying to run a simple query locally in Node JS using serverless - for the eventual purpose of uploading an Apollo Server API onto AWS Lambda.
However, I am not able to get anywhere near the deployment step as it appears that Node is unable to run a single instance of Apollo Server/Serverless locally in the first place due to a multitude of errors which shall be explained below:
Steps I have taken:
git clone the example API and follow all instructions here: https://github.com/fullstack-hy2020/rate-repository-api (I ensured everything works perfectly)
Follow all instructions on Apollographql up to "Running Server Locally": https://www.apollographql.com/docs/apollo-server/deployment/lambda/ - then run following command: serverless invoke local -f graphql -p query.json
ERROR - cannot use import statement outside module .... Solution - add "type": "module" to package.json - run command: serverless invoke local -f graphql -p query.json
ERROR - Cannot find module 'C:\Users\Julius\Documents\Web Development\rate-repository-api\src\utils\authService' imported from C:\Users\Julius\Documents\Web Development\rate-repository-api\src\apolloServer.js... Solution - install webpack as per solution here: Serverless does not recognise subdirectories in Node then run serverless invoke local -f graphql -p query.json
ERROR - Error [ERR_MODULE_NOT_FOUND]: Cannot find module 'C:\Users\Julius\Documents\Web Development\rate-repository-api\src\utils\authService' imported from C:\Users\Julius\Documents\Web Development\rate-repository-api\src\apolloServer.js
I do not know how to proceed from here, I am hoping that someone can point me in the right direction.
File Structure:
apolloServer.js:
import { ApolloServer, toApolloError, ApolloError } from '#apollo/server';
import { ValidationError } from 'yup';
import { startServerAndCreateLambdaHandler } from '#as-integrations/aws-lambda';
import AuthService from './utils/authService';
import createDataLoaders from './utils/createDataLoaders';
import logger from './utils/logger';
import { resolvers, typeDefs } from './graphql/schema';
const apolloErrorFormatter = (error) => {
logger.error(error);
const { originalError } = error;
const isGraphQLError = !(originalError instanceof Error);
let normalizedError = new ApolloError(
'Something went wrong',
'INTERNAL_SERVER_ERROR',
);
if (originalError instanceof ValidationError) {
normalizedError = toApolloError(error, 'BAD_USER_INPUT');
} else if (error.originalError instanceof ApolloError || isGraphQLError) {
normalizedError = error;
}
return normalizedError;
};
const createApolloServer = () => {
return new ApolloServer({
resolvers,
typeDefs,
formatError: apolloErrorFormatter,
context: ({ req }) => {
const authorization = req.headers.authorization;
const accessToken = authorization
? authorization.split(' ')[1]
: undefined;
const dataLoaders = createDataLoaders();
return {
authService: new AuthService({
accessToken,
dataLoaders,
}),
dataLoaders,
};
},
});
};
export const graphqlHandler = startServerAndCreateLambdaHandler(createApolloServer());
export default createApolloServer;
Serverless.yml:
service: apollo-lambda
provider:
name: aws
runtime: nodejs16.x
httpApi:
cors: true
functions:
graphql:
# Make sure your file path is correct!
# (e.g., if your file is in the root folder use server.graphqlHandler )
# The format is: <FILENAME>.<HANDLER>
handler: src/apolloServer.graphqlHandler
events:
- httpApi:
path: /
method: POST
- httpApi:
path: /
method: GET
custom:
webpack:
packager: 'npm'
webpackConfig: 'webpack.config.js' # Name of webpack configuration file
includeModules:
forceInclude:
- pg
Webpack.config.js
const path = require('path');
module.exports = {
mode: 'development',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'build'),
filename: 'foo.bundle.js',
},
};

Starting Plawywright Test Browser

guys. I'm trying to set up e2e testing using Playwright. I'm following along these steps (enter link description here) and I can see the tests are passing but I'd like to see the browser window so I can try and interact with the elements. How can I make the test runner open a browser window or tab?
You could either use the Debug mode by adding --debug to you command e.g.:
npx playwright test example --debug
This allows you to Debug through your Tests step by step.
Or you can change your config to run in headed mode by setting
headless:false
In you playwright.config.ts
You can have a global configuration file called playwright.config.ts which goes in project root, a basic example of which looks like below. Note the headless: false in the 'use' section. Change the 'baseURL' to what you want to test.
// playwright.config.ts
import { PlaywrightTestConfig } from '#playwright/test';
const config: PlaywrightTestConfig = {
reporter: [['list'], ['html', { open: 'never' }]],
workers: 1,
use: {
baseURL: http://playwright.dev,
headless: false,
},
projects: [
{
name: 'chromium',
use: {
browserName: 'chromium',
},
},
],
};
export default config;
In your test, because you have a baseURL set in config, you just need to call the following to navigate to that url:
// mytest.spec.ts
import { test } from '#playwright/test';
test('Do something...', async ({ page }) => {
await page.goto('');
});

Migrating cypress test from old version to latest version throws error

I am trying to migrate my test from Cypress 8.7.0 version to Cypress 10.10.0 version. Installed the latest version and did the below settings, but getting below error.
Using below versions:
Cypress 10.10.0,
"#badeball/cypress-cucumber-preprocessor": "^11.4.0",
node v18.4.0,
#bahmutov/cypress-esbuild-preprocessor": "^2.1.5"
Expected to find a global registry (this usually means you are trying to define steps or hooks in support/e2e.js, which is not supported) (this might be a bug, please report at https://github.com/badeball/cypress-cucumber-preprocessor)
Because this error occurred during a before each hook we are skipping all of the remaining tests.
I have added the error handling in e2e.js file and support/index.js file but still could not resolve this issue. I have .env file which has the environment variable in my root location. Could someone please advise on this issue ?
//Detail error log:
Because this error occurred during a `before each` hook we are skipping all of the remaining tests.
at fail (tests?p=tests/cypress/e2e/login/loginBase.feature:964:15)
at assert (tests?p=tests/cypress/e2e/login/loginBase.feature:971:9)
at assertAndReturn (tests?p=tests/cypress/e2e/login/loginBase.feature:975:9)
at getRegistry (tests?
Cypress version : v10.10.0
//tests/cypress/e2e/login/login.feature
#regression
#login
Feature: Login to base url
Scenario: Login to base url
Given I go to base url
//step defintion:
tests/cypress/stepDefinitions/login.cy.js
import { Given, When, Then, Before, After, And } from "#badeball/cypress-cucumber-preprocessor";
When('I go to base url', () => {
cy.visit(Cypress.config().baseUrl);
})
// tests/cypress/support/index.js file
// Import commands.js using ES2015 syntax:
import './commands'
Cypress.on('uncaught:exception', (err, runnable) => {
// returning false here prevents Cypress from
// failing the test
return false
});
//tests/cypress/support/e2e.js
// Import commands.js using ES2015 syntax:
import './commands'
Cypress.on('uncaught:exception', (err, runnable) => {
// returning false here prevents Cypress from
// failing the test
return false
})
//.cypress-cucumber-preprocessorrc.json // add this file in project root location
{
"stepDefinitions": [
"[filepath].{js,ts}",
"tests/cypress/stepDefinitions/**/*.{js,ts}"
]
}
// cypress.config.js
const { defineConfig } = require('cypress')
const createBundler = require("#bahmutov/cypress-esbuild-preprocessor");
const addCucumberPreprocessorPlugin = require("#badeball/cypress-cucumber-preprocessor")
const createEsbuildPlugin = require("#badeball/cypress-cucumber-preprocessor/esbuild").createEsbuildPlugin;
const dotenvPlugin = require('cypress-dotenv');
async function setupNodeEvents(on, config) {
await addCucumberPreprocessorPlugin.addCucumberPreprocessorPlugin(on, config);
on(
"file:preprocessor",
createBundler({
plugins: [createEsbuildPlugin(config)],
})
);
//webpack config goes here if required
config = dotenvPlugin(config)
return config;
}
module.exports = defineConfig({
e2e: {
baseUrl: 'https://bookmain.co',
apiUrl: 'https://bookmain.co/api/books/',
specPattern: "tests/cypress/e2e/**/*.feature",
supportFile: false,
setupNodeEvents
},
component: {
devServer: {
framework: "next",
bundler: "webpack",
},
},
});
// package.json
"cypress-cucumber-preprocessor": {
"nonGlobalStepDefinitions": true,
"stepDefinitions": "tests/cypress/stepDefinitions/**/*.{js,ts}",
"cucumberJson": {
"generate": true,
"outputFolder": "tests/cypress/cucumber-json",
"filePrefix": "",
"fileSuffix": ".cucumber"
}
},
In cypress.config.js add the following:
const {dotenvPlugin} = require('cypress-dotenv');
module.exports = (on, config) => {
config = dotenvPlugin(config)
return config
}
This will resolve the issue.

" Preset solid-jest not found." error when using jest

I would like to use jest and solid-jest to test one of my solid-js components. For this I created a configuration so that jest works solid-js. But, whenever I run the npm test command, I get the following error:
● Validation Error:
Preset solid-jest not found.
I searched for solutions on the Internet, but nothing about it. Here is the content of my jest.config.js file :
module.exports = async () => {
return {
verbose: true,
};
};
module.exports = {
preset: 'solid-jest',
testEnvironment: 'node',
transform: {
'^.+\\.jsx?$': 'solid-jest',
},
transformIgnorePatterns: ['./node_modules/'],
};
I don't know what's the problem.

Node.js setting up environment specific configs to be used with everyauth

I am using node.js + express.js + everyauth.js. I have moved all my everyauth logic into a module file
var login = require('./lib/everyauthLogin');
inside this I load my oAuth config file with the key/secret combinations:
var conf = require('./conf');
.....
twitter: {
consumerKey: 'ABC',
consumerSecret: '123'
}
These codes are different for different environments - development / staging / production as the callbacks are to different urls.
Question: How do I set these in the environmental config to filter through all modules or can I pass the path directly into the module?
Set in env:
app.configure('development', function(){
app.set('configPath', './confLocal');
});
app.configure('production', function(){
app.set('configPath', './confProduction');
});
var conf = require(app.get('configPath'));
Pass in
app.configure('production', function(){
var login = require('./lib/everyauthLogin', {configPath: './confProduction'});
});
? hope that makes sense
My solution,
load the app using
NODE_ENV=production node app.js
Then setup config.js as a function rather than an object
module.exports = function(){
switch(process.env.NODE_ENV){
case 'development':
return {dev setting};
case 'production':
return {prod settings};
default:
return {error or other settings};
}
};
Then as per Jans solution load the file and create a new instance which we could pass in a value if needed, in this case process.env.NODE_ENV is global so not needed.
var Config = require('./conf'),
conf = new Config();
Then we can access the config object properties exactly as before
conf.twitter.consumerKey
You could also have a JSON file with NODE_ENV as the top level. IMO, this is a better way to express configuration settings (as opposed to using a script that returns settings).
var config = require('./env.json')[process.env.NODE_ENV || 'development'];
Example for env.json:
{
"development": {
"MONGO_URI": "mongodb://localhost/test",
"MONGO_OPTIONS": { "db": { "safe": true } }
},
"production": {
"MONGO_URI": "mongodb://localhost/production",
"MONGO_OPTIONS": { "db": { "safe": true } }
}
}
A very useful solution is use the config module.
after install the module:
$ npm install config
You could create a default.json configuration file. (you could use JSON or JS object using extension .json5 )
For example
$ vi config/default.json
{
"name": "My App Name",
"configPath": "/my/default/path",
"port": 3000
}
This default configuration could be override by environment config file or a local config file for a local develop environment:
production.json could be:
{
"configPath": "/my/production/path",
"port": 8080
}
development.json could be:
{
"configPath": "/my/development/path",
"port": 8081
}
In your local PC you could have a local.json that override all environment, or you could have a specific local configuration as local-production.json or local-development.json.
The full list of load order.
Inside your App
In your app you only need to require config and the needed attribute.
var conf = require('config'); // it loads the right file
var login = require('./lib/everyauthLogin', {configPath: conf.get('configPath'));
Load the App
load the app using:
NODE_ENV=production node app.js
or setting the correct environment with forever or pm2
Forever:
NODE_ENV=production forever [flags] start app.js [app_flags]
PM2 (via shell):
export NODE_ENV=staging
pm2 start app.js
PM2 (via .json):
process.json
{
"apps" : [{
"name": "My App",
"script": "worker.js",
"env": {
"NODE_ENV": "development",
},
"env_production" : {
"NODE_ENV": "production"
}
}]
}
And then
$ pm2 start process.json --env production
This solution is very clean and it makes easy set different config files for Production/Staging/Development environment and for local setting too.
In brief
This kind of a setup is simple and elegant :
env.json
{
"development": {
"facebook_app_id": "facebook_dummy_dev_app_id",
"facebook_app_secret": "facebook_dummy_dev_app_secret",
},
"production": {
"facebook_app_id": "facebook_dummy_prod_app_id",
"facebook_app_secret": "facebook_dummy_prod_app_secret",
}
}
common.js
var env = require('env.json');
exports.config = function() {
var node_env = process.env.NODE_ENV || 'development';
return env[node_env];
};
app.js
var common = require('./routes/common')
var config = common.config();
var facebook_app_id = config.facebook_app_id;
// do something with facebook_app_id
To run in production mode :
$ NODE_ENV=production node app.js
In detail
This solution is from : http://himanshu.gilani.info/blog/2012/09/26/bootstraping-a-node-dot-js-app-for-dev-slash-prod-environment/, check it out for more detail.
The way we do this is by passing an argument in when starting the app with the environment. For instance:
node app.js -c dev
In app.js we then load dev.js as our configuration file. You can parse these options with optparse-js.
Now you have some core modules that are depending on this config file. When you write them as such:
var Workspace = module.exports = function(config) {
if (config) {
// do something;
}
}
(function () {
this.methodOnWorkspace = function () {
};
}).call(Workspace.prototype);
And you can call it then in app.js like:
var Workspace = require("workspace");
this.workspace = new Workspace(config);
An elegant way is to use .env file to locally override production settings.
No need for command line switches. No need for all those commas and brackets in a config.json file. See my answer here
Example: on my machine the .env file is this:
NODE_ENV=dev
TWITTER_AUTH_TOKEN=something-needed-for-api-calls
My local .env overrides any environment variables. But on the staging or production servers (maybe they're on heroku.com) the environment variables are pre-set to stage NODE_ENV=stage or production NODE_ENV=prod.
Set environment variable in deployment server (ex: like NODE_ENV=production). You can access your environmental variable through process.env.NODE_ENV.
Find the following config file for the global settings
const env = process.env.NODE_ENV || "development"
const configs = {
base: {
env,
host: '0.0.0.0',
port: 3000,
dbPort: 3306,
secret: "secretKey for sessions",
dialect: 'mysql',
issuer : 'Mysoft corp',
subject : 'some#user.com',
},
development: {
port: 3000,
dbUser: 'root',
dbPassword: 'root',
},
smoke: {
port: 3000,
dbUser: 'root',
},
integration: {
port: 3000,
dbUser: 'root',
},
production: {
port: 3000,
dbUser: 'root',
}
};
const config = Object.assign(configs.base, configs[env]);
module.exports= config;
"base" contains common config for all environments.
Then import in other modules like:
const config = require('path/to/config.js')
console.log(config.port)
Happy Coding...
How about doing this in a much more elegant way with nodejs-config module.
This module is able to set configuration environment based on your computer's name. After that when you request a configuration you will get environment specific value.
For example lets assume your have two development machines named pc1 and pc2 and a production machine named pc3. When ever you request configuration values in your code in pc1 or pc2 you must get "development" environment configuration and in pc3 you must get "production" environment configuration. This can be achieved like this:
Create a base configuration file in the config directory, lets say "app.json" and add required configurations to it.
Now simply create folders within the config directory that matches your environment name, in this case "development" and "production".
Next, create the configuration files you wish to override and specify the options for each environment at the environment directories(Notice that you do not have to specify every option that is in the base configuration file, but only the options you wish to override. The environment configuration files will "cascade" over the base files.).
Now create new config instance with following syntax.
var config = require('nodejs-config')(
__dirname, // an absolute path to your applications 'config' directory
{
development: ["pc1", "pc2"],
production: ["pc3"],
}
);
Now you can get any configuration value without worrying about the environment like this:
config.get('app').configurationKey;
This answer is not something new. It's similar to what #andy_t has mentioned. But I use the below pattern for two reasons.
Clean implementation with No external npm dependencies
Merge the default config settings with the environment based settings.
Javascript implementation
const settings = {
_default: {
timeout: 100
baseUrl: "http://some.api/",
},
production: {
baseUrl: "http://some.prod.api/",
},
}
// If you are not using ECMAScript 2018 Standard
// https://stackoverflow.com/a/171256/1251350
module.exports = { ...settings._default, ...settings[process.env.NODE_ENV] }
I usually use typescript in my node project. Below is my actual implementation copy-pasted.
Typescript implementation
const settings: { default: ISettings, production: any } = {
_default: {
timeout: 100,
baseUrl: "",
},
production: {
baseUrl: "",
},
}
export interface ISettings {
baseUrl: string
}
export const config = ({ ...settings._default, ...settings[process.env.NODE_ENV] } as ISettings)

Resources