Last active
August 31, 2022 07:16
-
-
Save saschwarz/b7f115ab6a7765ff5e45b9b9461cf895 to your computer and use it in GitHub Desktop.
Automated Azure AD login and session token capture to json file for reading by Cypress commands. Heavily inspired by https://gist.github.com/pieterdv/82773fbe036719479d76ab0a4985dc3b
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const API = Cypress.env('API'); | |
const headers = { | |
Authorization: '', | |
}; | |
Cypress.Commands.add('loginUser', () => { | |
return cy.readFile('aad-tokens.json') | |
.then(creds => { | |
// set auth headers so test setup calls are authorized | |
headers.Authorization = `Bearer ${creds['msal.idtoken']}`; | |
// put MS Azure AD creds in session storage | |
// so application under test will be logged in. | |
for (let key in creds) { | |
if ( | |
key.startsWith('msal.') || | |
key.startsWith('{"authority":') | |
) { | |
sessionStorage[key] = creds[key]; | |
} | |
} | |
}); | |
}); | |
// example of custom command using headers configured via loginUser | |
Cypress.Commands.add('APICreate', (url, instance) => { | |
Cypress.log({ | |
name: 'APICreate', | |
message: url + ' | ' + JSON.stringify(instance) | |
}) | |
return cy.request({ | |
method: 'POST', | |
headers: headers, | |
url: `${API}/${url}`, | |
body: instance | |
}).then(data => data.body); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const fs = require('fs'); | |
const puppeteer = require('puppeteer'); | |
const commander = require('commander'); | |
const inquirer = require('inquirer'); | |
const util = require('util'); | |
const readFile = util.promisify(fs.readFile); | |
const getAdToken = function(config) { | |
console.log(`Logging in ${config.email} at ${config.appURI}`); | |
return puppeteer.launch({ headless: true }).then(async browser => { | |
try { | |
const page = await browser.newPage(); | |
await page.goto(config.appURI); | |
await page.waitFor(3000); | |
await page.click('input[name=passwd]'); | |
await page.type('input[name=loginfmt]', config.email, { | |
delay: 50 | |
}); | |
await page.waitFor(500); | |
await page.click('input[type=submit]'); | |
await page.waitFor(500); | |
await page.click('input[name=passwd]'); | |
await page.waitFor(500); | |
await page.type('input[name=passwd]', config.password, { | |
delay: 50 | |
}); | |
await page.waitFor(500); | |
await page.click('input[type=submit]'); | |
await page.waitForSelector('.nav-link', { visible: true, delay: 3000 }); | |
const aadValues = await page.evaluate((conf) => { | |
for (let i = 0, len = sessionStorage.length; i < len; ++i) { | |
if ( | |
sessionStorage.key(i).startsWith('msal.') || | |
sessionStorage.key(i).startsWith('{"authority":') | |
) { | |
conf[sessionStorage.key(i)] = sessionStorage.getItem( | |
sessionStorage.key(i) | |
); | |
} | |
} | |
return conf; | |
}, config); | |
browser.close(); | |
fs.readFile('aad-tokens.json', 'utf8', (err, data) => { | |
fs.writeFile('aad-tokens.json', JSON.stringify(aadValues), { encoding: 'utf8' }, | |
(error) => { | |
if (error) { | |
console.log(error); | |
} | |
}); | |
}); | |
console.log(`aad-tokens.json updated`); | |
} catch (error) { | |
console.log(error); | |
browser.close(); | |
} | |
}); | |
}; | |
const promptUser = async function(defaults) { | |
const config = await inquirer.prompt([{ | |
name: 'appURI', | |
message: 'App URI:', | |
default: defaults.appURI | |
}, | |
{ | |
name: 'email', | |
message: 'Email:', | |
default: defaults.email | |
}, | |
{ | |
name: 'password', | |
message: 'Password:', | |
default: defaults.password | |
}, | |
]); | |
await fs.writeFile('./aad-tokens.json', | |
JSON.stringify(config), { encoding: 'utf8' }, | |
(error) => { | |
if (error) { | |
console.log(error); | |
} | |
}); | |
return config; | |
}; | |
const loginUser = function(prompt = false) { | |
Promise.resolve().then(async() => { | |
let config = await readFile('./aad-tokens.json', 'utf-8') | |
.then(file => JSON.parse(file)) | |
.catch(e => { | |
return { | |
appURI: 'http://localhost:4200/app/', | |
email: '', | |
password: '', | |
}; | |
}); | |
if (prompt) { | |
config = await promptUser(config); | |
} | |
getAdToken(config); | |
}); | |
}; | |
const main = () => { | |
commander | |
.option('--no-prompt', 'Do not prompt for input and accept values from aad-tokens.json', false) | |
.parse(process.argv); | |
loginUser(commander.prompt); | |
}; | |
module.exports = { | |
getAdToken: getAdToken, | |
loginUser: loginUser, | |
}; | |
main(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
... | |
"scripts": { | |
"cypress": "node getadtoken.js --no-prompt && cypress open --env API=https://example.com/data/v4", | |
"login": "node getadtoken.js" | |
}, | |
... |
Sorry @nikkieta I'm no longer working on that project and no longer have an environment to test.
Things to check:
-
that you actually have a valid token in the file
-
you see the token is in header of the test API calls when you inspect them in Cypress
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I am trying to login to https://login.microsoftonline.com using puppeter above mentioned code. getadtokens.js
Calling LoginUser in my spec in Cypress. using below code.
describe('Homepage', () => {
it('Does not do much!', function() {
cy.loginUser();
});
});
Nothing happens in Cypress test runner. Not able to see the UI which we have already logged in using Commands.js.
Please share if i m missing anything. How can we proceed with the test cases. even we tried adding cy.visit("https://test.ci.ai.dynamics.com") after cy.loginUser(); but got error as microsoftonline refused to connect.