Skip to content

Instantly share code, notes, and snippets.

@ElvisLives
Forked from csuzw/index.js
Created November 7, 2019 21:07
Show Gist options
  • Save ElvisLives/7c99c2b85ae5ac7f384f836ace8c8289 to your computer and use it in GitHub Desktop.
Save ElvisLives/7c99c2b85ae5ac7f384f836ace8c8289 to your computer and use it in GitHub Desktop.
Azure AD Single Sign On with Cypress
// This goes in cypress/plugins/index.js
const AzureAdSingleSignOn = require('./azure-ad-sso/plugin').AzureAdSingleSignOn
module.exports = (on, config) => {
on('task', {AzureAdSingleSignOn:AzureAdSingleSignOn})
}
// This is an example of how you might use the plugin in your tests
describe('My spec', function() {
Cypress.Commands.add('setCookies', function () {
const options = {
username: Cypress.env('username'),
password: Cypress.env('password'),
loginUrl: Cypress.env('appUrl'),
postLoginSelector: '#myselector',
headless: true,
logs: false
}
cy.task('AzureAdSingleSignOn', options).then(result => {
cy.clearCookies()
result.cookies.forEach(cookie => {
cy.setCookie(cookie.name, cookie.value, {
domain: cookie.domain,
expiry: cookie.expires,
httpOnly: cookie.httpOnly,
path: cookie.path,
secure: cookie.secure
})
Cypress.Cookies.preserveOnce(cookie.name)
})
})
})
before(function() {
cy.setCookies();
})
it('Visits the site as logged in user', function() {
cy.visit(Cypress.env('appUrl'));
cy.contains(`Hello, ${Cypress.env('username')}!`)
})
})
// I put this in cypress/plugins/azure-ad-sso directory
'use strict'
const puppeteer = require('puppeteer')
/**
*
* @param {options.username} string username
* @param {options.password} string password
* @param {options.loginUrl} string password
* @param {options.postLoginSelector} string a selector on the app's post-login return page to assert that login is successful
* @param {options.headless} boolean launch puppeteer in headless more or not
* @param {options.logs} boolean whether to log cookies and other metadata to console
* @param {options.getAllBrowserCookies} boolean whether to get all browser cookies instead of just for the loginUrl
*/
module.exports.AzureAdSingleSignOn = async function AzureAdSingleSignOn(options = {}) {
validateOptions(options)
const browser = await puppeteer.launch({ headless: !!options.headless })
const page = await browser.newPage()
await page.goto(options.loginUrl)
await typeUsername({ page, options })
await typePassword({ page, options })
const cookies = await getCookies({ page, options })
await finalizeSession({ page, browser, options })
return {
cookies
}
}
function validateOptions(options) {
if (!options.username || !options.password) {
throw new Error('Username or Password missing for login')
}
if (!options.loginUrl) {
throw new Error('Login Url missing')
}
if (!options.postLoginSelector) {
throw new Error('Post login selector missing')
}
}
async function typeUsername({ page, options } = {}) {
await page.waitForSelector('input[name=loginfmt]:not(.moveOffScreen)', { visible: true, delay: 10000 })
await page.type('input[name=loginfmt]', options.username, { delay: 50 })
await page.click('input[type=submit]')
}
async function typePassword({ page, options } = {}) {
await page.waitForSelector('input[name=Password]:not(.moveOffScreen),input[name=passwd]:not(.moveOffScreen)', { visible: true, delay: 10000 })
await page.type('input[name=passwd]', options.password, { delay: 50 })
await page.click('input[type=submit]')
}
async function getCookies({ page, options } = {}) {
await page.waitForSelector(options.postLoginSelector, { visible: true, delay: 10000 })
const cookies = options.getAllBrowserCookies
? await getCookiesForAllDomains(page)
: await page.cookies(options.loginUrl)
if (options.logs) {
console.log(cookies)
}
return cookies
}
async function getCookiesForAllDomains(page) {
const cookies = await page._client.send('Network.getAllCookies', {})
return cookies.cookies
}
async function finalizeSession({ page, browser, options } = {}) {
await browser.close()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment