Skip to content

Instantly share code, notes, and snippets.

@jkosters
Created January 12, 2019 00:19
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jkosters/63726a89f8e2be396c4c1675eca90837 to your computer and use it in GitHub Desktop.
Save jkosters/63726a89f8e2be396c4c1675eca90837 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/saschwarz/b7f115ab6a7765ff5e45b9b9461cf895
const api = Cypress.env("API");
const headers = {
Authorization: ""
};
Cypress.Commands.add("loginUser", () => {
return cy.readFile("aad-tokens.json")
.then(credentials => {
// set auth headers so test setup calls are authorized
headers.Authorization = `Bearer ${credentials["msal.idtoken"]}`;
// put MS Azure AD creds in session storage
// so application under test will be logged in.
for (let key in credentials) {
if (credentials.hasOwnProperty(key)) {
if (
key.startsWith("msal.") ||
key.startsWith('{"authority":')
) {
sessionStorage[key] = credentials[key];
}
}
}
});
});
// example of custom command using headers configured via loginUser
Cypress.Commands.add("APICreate", (url, instance) => {
window.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);
});
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 aadToken = {
filename: "aad-tokens.json",
filepath: `./aad-tokens.json`,
encoding: "utf8",
defaultValues: {
appURI: "http://localhost:4200/app/",
email: "",
password: ""
},
selectors: {
usernameInput: "input[name=loginfmt]",
passwordInput: "input[name=Password]",
submitInput: "input[type=submit]",
submitButton: "#submitButton",
domainPage: '#appId'
}
};
const onWriteFileError = (error) => {
if (error) {
console.log(error);
}
};
const writeAadTokenFile = function (aadTokenValues) {
return fs.writeFile(aadToken.filename,
JSON.stringify(aadTokenValues),
{ encoding: aadToken.encoding },
onWriteFileError);
};
const collectAadValuesFromSessionStorage = (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;
};
const createWaitOptions = function (delayInMs = 3000) {
return { visible: true, delay: delayInMs };
};
const getAdToken = function (config) {
console.log(`Logging in ${config.email} at ${config.appURI}`);
return puppeteer.launch({ headless: false }).then(async browser => {
try {
const page = await browser.newPage();
await page.goto(config.appURI);
await page.waitForSelector(aadToken.selectors.usernameInput, createWaitOptions(3000));
await page.type(aadToken.selectors.usernameInput, config.email, {
delay: 50
});
await page.click(aadToken.selectors.submitInput);
console.log(`Username submitted`);
await page.waitForSelector(aadToken.selectors.passwordInput, createWaitOptions(10000));
await page.type(aadToken.selectors.passwordInput, config.password, {
delay: 50
});
await page.click(aadToken.selectors.submitButton);
console.log(`password submitted`);
await page.waitForSelector(aadToken.selectors.submitInput, createWaitOptions(1000));
await page.click(aadToken.selectors.submitInput);
console.log(`Do save credentials submitted`);
page.waitForNavigation();
await page.waitForXPath(aadToken.xpath.domainPage, createWaitOptions(10000));
const aadValues = await page.evaluate(collectAadValuesFromSessionStorage, config);
browser.close();
console.log(`aad values collected`);
fs.readFile(aadToken.filename, aadToken.encoding, () => writeAadTokenFile(aadValues));
console.log(`${aadToken.filename} 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,
type: "password"
}
]);
await writeAadTokenFile(config);
return config;
};
const loginUser = function (prompt = false) {
Promise.resolve().then(async () => {
let config = await readFile(aadToken.filepath, aadToken.encoding)
.then(file => JSON.parse(file))
.catch(() => aadToken.defaultValues);
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();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment