bjowes / cypress-ntlm-auth

Windows authentication plugin for Cypress
MIT License
55 stars 10 forks source link

Not able to read different config files based on environment along with ntlm config #123

Closed hari49951 closed 4 years ago

hari49951 commented 4 years ago

@bjowes Hi, I am trying to read different config files along with ntlm config. I am not sure how to do that. can you please suggest how to read both files?

const fs = require('fs-extra') const path = require('path') const cucumber = require('cypress-cucumber-preprocessor').default; const ntlmAuth = require("cypress-ntlm-auth/dist/plugin"); /**

}

function getConfigurationByFile(file) { const pathToConfigFile = path.resolve( 'cypress/config', cypress.${file}.json ); return fs.readJson(pathToConfigFile) }

bjowes commented 4 years ago

Hi @hari49951 - using multiple config files should work fine, it seems you are already following the examples from the cypress docs. What you need to change is the order of execution. The line config = ntlmAuth.initNtlmAuth(config); adds properties to the config, but when you do return getConfigurationByFile(file) after it, those changes are ignored.

Try this way:

const file = config.env.configFile || 'test'
config = getConfigurationByFile(file);
config = ntlmAuth.initNtlmAuth(config);
return config;
hari49951 commented 4 years ago

Hi @bjowes thank you so much for the quick reply. I modified the code as you suggested and after trying open cypress test runner below is error I am getting. Is there something I am missing? Appreciate you help!

The function exported by the plugins file threw an error.

We invoked the function exported by C:\Users{pathtoproject}\cypress\plugins\index.js, but it threw an error.

TypeError: Cannot set property 'NTLM_AUTH_PROXY' of undefined at setupProxyEnvironment (C:\Users{pathtoproject}\node_modules\cypress-ntlm-auth\dist\plugin\index.js:23:32) at C:\Users{pathtoproject}\node_modules\cypress-ntlm-auth\dist\plugin\index.js:32:22 at new Promise () at Object.initNtlmAuth (C:\Users{pathtoproject}\node_modules\cypress-ntlm-auth\dist\plugin\index.js:28:12) at module.exports (C:\Users{pathtoproject}\cypress\plugins\index.js:27:21) at C:\Users\AppData\Local\Cypress\Cache\4.8.0\Cypress\resources\app\packages\server\lib\plugins\child\run_plugins.js:78:12 at tryCatcher (C:\Users\AppData\Local\Cypress\Cache\4.8.0\Cypress\resources\app\packages\server\node_modules\bluebird\js\release\util.js:16:23) at Function.Promise.attempt.Promise.try (C:\Users\AppData\Local\Cypress\Cache\4.8.0\Cypress\resources\app\packages\server\node_modules\bluebird\js\release\method.js:39:29) at load (C:\Users\AppData\Local\Cypress\Cache\4.8.0\Cypress\resources\app\packages\server\lib\plugins\child\run_plugins.js:75:7) at EventEmitter. (C:\Users\AppData\Local\Cypress\Cache\4.8.0\Cypress\resources\app\packages\server\lib\plugins\child\run_plugins.js:231:5) at EventEmitter.emit (events.js:210:5) at process. (C:\Users\AppData\Local\Cypress\Cache\4.8.0\Cypress\resources\app\packages\server\lib\plugins\util.js:19:22) at process.emit (events.js:210:5) at emit (internal/child_process.js:876:12) at processTicksAndRejections (internal/process/task_queues.js:81:21)

code after change: const fs = require('fs-extra') const path = require('path') const cucumber = require('cypress-cucumber-preprocessor').default; const ntlmAuth = require("cypress-ntlm-auth/dist/plugin"); /**

function getConfigurationByFile(file) { const pathToConfigFile = path.resolve( 'cypress/config', cypress.${file}.json ); return fs.readJson(pathToConfigFile) }

Update: Now I am not able to run cypress as I do before "npm run cypress-ntlm". I see an error in index.js file, please refer to attached image.

cypress-ntlm
testtek commented 4 years ago

@hari49951 try this

const ntlmAuth = require('cypress-ntlm-auth/dist/plugin'); const fs = require('fs-extra'); const path = require('path');

const getConfigurationByFile = async (config) => { const file = config.env.configFile || 'dev'; const pathToConfigFile = path.resolve('cypress/', 'config', ${file}.json); return fs.readJson(pathToConfigFile); };

module.exports = async (on, config) => { config = await getConfigurationByFile(config); await ntlmAuth.initNtlmAuth(config); return config; };

hari49951 commented 4 years ago

Hi @testtek thanks for the reply. When I try above solution, getting the below error.

The plugins file is missing or invalid. Your pluginsFile is set to C:\Users{pathtoproject}\cypress\plugins\index.js, but either the file is missing, it contains a syntax error, or threw an error when required. The pluginsFile must be a .js or .coffee file. Or you might have renamed the extension of your pluginsFile to .ts. If that's the case, restart the test runner. Please fix this, or set pluginsFile to false if a plugins file is not necessary for your project. C:\Users{pathtoproject}\cypress\plugins\index.js:34 config = await getConfigurationByFile(config); ^^^^^ SyntaxError: await is only valid in async function at Module._compile (internal/modules/cjs/loader.js:896:18) at Object.Module._extensions..js (internal/modules/cjs/loader.js:986:10) at Module.load (internal/modules/cjs/loader.js:816:32) at Module._load (internal/modules/cjs/loader.js:728:14) at Module._load (electron/js2c/asar.js:717:26) at Function.Module._load (electron/js2c/asar.js:717:26) at Module.require (internal/modules/cjs/loader.js:853:19) at require (internal/modules/cjs/helpers.js:74:18) at module.exports (C:\Users\AppData\Local\Cypress\Cache\4.8.0\Cypress\resources\app\packages\server\lib\plugins\child\run_plugins.js:208:15) at Object. (C:\Users\AppData\Local\Cypress\Cache\4.8.0\Cypress\resources\app\packages\server\lib\plugins\child\index.js:9:25) at Module._compile (internal/modules/cjs/loader.js:968:30) at Object.Module._extensions..js (internal/modules/cjs/loader.js:986:10) at Module.load (internal/modules/cjs/loader.js:816:32) at Module._load (internal/modules/cjs/loader.js:728:14) at Module._load (electron/js2c/asar.js:717:26) at Function.Module._load (electron/js2c/asar.js:717:26)

bjowes commented 4 years ago

The variant from @testtek adds async execution, but it won't change the result. Also, the return value from initNtlmAuth must be returned from the function.

If you go back to my suggestion, I think the issue is that initNtlmAuth assumes that the config object contains a "env" property, which it will always do when the config object comes from cypress itself. When you read the config directly from a json file, this might not be true. You could add an empty env property in your config files with a line like "env": {}

Or you can modify the code slightly to add it for you, so you don't need to pollute the config files with it. Add it like this

config = getConfigurationByFile(file);
config.env = {};
config = ntlmAuth.initNtlmAuth(config);
hari49951 commented 4 years ago

Hi @bjowes, thanks a lot. It worked but I need to use "env": {} in config file and config.env = {}; in plugin. However after running a test on cypress test runner, I am getting another error. I am using "npm run cypress-ntlm" to open test runner. Scripts--> "cypress-ntlm": "npm run ntlm-proxy && (cypress-ntlm open --env configFile=test & ntlm-proxy-exit)",

Error The cypress-ntlm-auth plugin must be loaded before using this method node_modules/cypress-ntlm-auth/dist/commands/index.js:22:1 20 | const ntlmConfigApi = Cypress.env('NTLM_AUTH_API'); 21 | if (!ntlmProxy || !ntlmConfigApi) {

22 | throw new Error('The cypress-ntlm-auth plugin must be loaded before using this method'); | ^ 23 | } 24 | let ntlmConfig = { 25 | ntlmHost: ntlmHost,

bjowes commented 4 years ago

Wierd, that indicates that the config object is not updated. Could you paste your plugin file again? Make sure you are returning the config object from the module.exports = (on, config) => method.

hari49951 commented 4 years ago

@bjowes Here is the plugins/index.js file. Given config file is loading (In test ruuner settings/config section I can see the data that I want to use) which has test data and env data like url, username and password. Test is failing at cy.ntlm() request.

const fs = require('fs-extra') const path = require('path') const cucumber = require('cypress-cucumber-preprocessor').default; const ntlmAuth = require("cypress-ntlm-auth/dist/plugin");

/**

function getConfigurationByFile(file) { const pathToConfigFile = path.resolve( 'cypress/config', ${file}.json ); return fs.readJson(pathToConfigFile) }

hari49951 commented 4 years ago

@bjowes I don't see these NTLM_AUTH_PROXY, NTLM_AUTH_API under settings/configuration tab from cypress test runner while loading config file other than default cypress.json file using cypress-ntlm-auth. If I load default cypress.json then I can see these NTLM_AUTH_PROXY, NTLM_AUTH_API under settings/configuration tab from cypress test runner. Appreciate you help on this issue

bjowes commented 4 years ago

Hi @hari49951 - sorry to keep you waiting, I've had some time away from coding. I reproduced this on my own machine and found that fs.readJson is actually an async function (returns a promise). All the solutions I've suggested assumed it was a synchronous function. To use fs.readJson, do something like this:

module.exports = (on, config) => {
  // on is used to hook into various events Cypress emits
  // config is the resolved Cypress config
  on('file:preprocessor', cucumber());
  const file = config.env.configFile || 'test'
  return getConfigurationByFile(file).then((config) => {
    config.env = {};
    return ntlmAuth.initNtlmAuth(config);
  });
};
hari49951 commented 4 years ago

Hi @bjowes Thanks for taking time to checking on this issue. I have tried your above solution and now I see that test config file is being loaded under settings/configuration tab from cypress test runner but values are from default cypress.json file. It's seems wired. Please go through below details and correct me if I am missing anything.

plugins/index.js file: module.exports = (on, config) => { // on is used to hook into various events Cypress emits // config is the resolved Cypress config on('file:preprocessor', cucumber()); const file = config.env.configFile || 'test' return getConfigurationByFile(file).then((config) => { config.env = {}; return ntlmAuth.initNtlmAuth(config); }); };

function getConfigurationByFile(file) { const pathToConfigFile = path.resolve( 'cypress/config', ${file}.json ); return fs.readJson(pathToConfigFile) }

Scenario A. Loading test.json (npm run cypress:open:qa where cypress:open:qa => "npm run ntlm-proxy && (cypress-ntlm open --env configFile=test & ntlm-proxy-exit)") test.json file: { "baseUrl": "https://baseurl.com", "video": false, "defaultCommandTimeout": 10000, "pageLoadTimeout": 40000, "ignoreTestFiles": [".js",".md"], "testFiles": "*/.{feature,features}", "env": { "AuthUrl": "https://hosturlfromtest.jon", "username": "testuserfromtest.json", "password": "testpassfromtest.json" } }

values under settings tab: baseUrl:"https://baseurl.com" fixturesFolder:"cypress/fixtures" blacklistHosts:null chromeWebSecurity:true modifyObstructiveCode:true integrationFolder:"cypress/integration" env: AuthUrl:"https://somehosturlfromcypress.json" username:"testuserfromcypress.json" password:"testpassfromcypress.json" configFile:"test" NTLM_AUTH_PROXY:"http://127.0.0.1:51415" NTLM_AUTH_API:"http://127.0.0.1:51414" pluginsFile:"cypress/plugins" hosts:null

Scenario B: Loading default cypress.json (npm run cypress-ntlm where cypress-ntlm ==> "npm run ntlm-proxy && (cypress-ntlm open & ntlm-proxy-exit)")

Cypress.json file: { "baseUrl": "https://baseurl.com", "video": true, "defaultCommandTimeout": 10000, "pageLoadTimeout": 40000, "ignoreTestFiles": [ ".js", ".md" ], "testFiles": "*/.{feature,features}", "env": { "AuthUrl": "https://somehosturlfromcypress.json", "username": "testuserfromcypress.json", "password": "testpassfromcypress.json" } }

values under settings tab: baseUrl:"https://baseurl.com" fixturesFolder:"cypress/fixtures" blacklistHosts:null chromeWebSecurity:true modifyObstructiveCode:true integrationFolder:"cypress/integration" env: AuthUrl:"https://somehosturlfromcypress.json" username:"testuserfromcypress.json" password:"testpassfromcypress.json" NTLM_AUTH_PROXY:"http://127.0.0.1:51260" NTLM_AUTH_API:"http://127.0.0.1:51259" pluginsFile:"cypress/plugins" hosts:null

bjowes commented 4 years ago

I see that you now have content inside the env property in your custom config file. Then you must remove the line config.env = {} since it clears the env property. It is only needed if env is null.

Also, did you look into the —config-file Argument to cypress? I think it could also solve what you are trying to achieve without so much code in the plugins file. https://docs.cypress.io/guides/guides/command-line.html#cypress-run-config-file-lt-config-file-gt

hari49951 commented 4 years ago

@bjowes Thank you so much, now I am able to load different config files. And the document is also informative.