New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
End to End test framework for MSAL 1.0 and 2.0 #1393
Conversation
"@azure/msal-browser", | ||
"@azure/msal-angular", | ||
"vanilla-js-test-app", | ||
"vanilla-js-test-app-2.0" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we confirm msal-node works even with dummy tests? Or is that not a concern?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wait! Is this only browser specific end-to-end?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can include all end to end tests with this command, I will change the name to reflect this. For msal-browser and msal-core, the end to end tests are all browser based.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can add whatever sample runs your node end to end tests when you have it created.
let username = ""; | ||
let accountPwd = ""; | ||
|
||
function setupScreenshotDir() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
are screenshots checked in?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no they are ignored
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
overall looks great, I personally think there could be value in having something like a TestUtils
or TestConstants
file that encompasses much of the shared code and strings, because a lot of this stuff is repeated
|
||
private async requestLabApi(endpoint: string, accessToken: string): Promise<any> { | ||
try { | ||
const response = await axios(`${labApiUri}${endpoint}`, { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
axios
is the client we're also using for node, right? wanted to make sure there was consistency
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes thats correct, just wanted something simple to use.
async function enterCredentials(page: puppeteer.Page, testName: string): Promise<void> { | ||
await page.waitForNavigation({ waitUntil: "networkidle0"}); | ||
await takeScreenshot(page, testName, `loginPage`); | ||
await page.type("#i0116", username); | ||
await page.click("#idSIButton9"); | ||
await page.waitForNavigation({ waitUntil: "networkidle0"}); | ||
await takeScreenshot(page, testName, `pwdInputPage`); | ||
await page.type("#i0118", accountPwd); | ||
await page.click("#idSIButton9"); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
since I'm less familiar with puppeteer, my understanding is that this flow is basically:
- navigate to a page
- take a screenshot of the page
- crawl the screenshot to verify data is correct
is this all correct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No the screenshot is more of utility thing. The crawling occurs on the headless browser page.
let browser: puppeteer.Browser; | ||
before(async () => { | ||
setupScreenshotDir(); | ||
browser = await puppeteer.launch(); | ||
}); | ||
|
||
let context: puppeteer.BrowserContext; | ||
let page: puppeteer.Page; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i'm assuming that the context
and page
are not declared at the top because their values depend on puppeteer.launch()
, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we create a new context and page for each test so we have a fresh environment. browser doesn't need to be reloaded every time.
let username = ""; | ||
let accountPwd = ""; | ||
|
||
function setupScreenshotDir() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
since this is implemented in most of these test files, can we just implement it in one place and import each time?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this looks like it could apply to a few functions, like takeScreenshot
and potentially setupCredentials
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes I am working on creating some test utilities, i will add them as a part of a separate PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1
await page.waitForNavigation({ waitUntil: "networkidle0"}); | ||
await takeScreenshot(page, testName, `loginPage`); | ||
await page.type("#i0116", username); | ||
await page.click("#idSIButton9"); | ||
await page.waitForNavigation({ waitUntil: "networkidle0"}); | ||
await takeScreenshot(page, testName, `pwdInputPage`); | ||
await page.type("#i0118", accountPwd); | ||
await page.click("#idSIButton9"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should all of these strings be constants?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will enhance some of this in a future PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1
@@ -19,8 +18,8 @@ const loginRequest = { | |||
|
|||
// Add here the endpoints for MS Graph API services you would like to use. | |||
const graphConfig = { | |||
graphMeEndpoint: "Enter_the_Graph_Endpoint_Herev1.0/me", | |||
graphMailEndpoint: "Enter_the_Graph_Endpoint_Herev1.0/me/messages" | |||
graphMeEndpoint: "https://graph.microsoft-ppe.com/v1.0/me", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we be using pre-production endpoints?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We do for 2.0 until we have a test app that works. I am contacting the labs team to set one up for us.
}); | ||
return response.data; | ||
} catch (e) { | ||
console.error(e); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Re-throw instead of returning null?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm going to enhance some of these test utilities in a future PR. for now just getting e2e working.
import axios from "axios"; | ||
const labApiUri = "https://msidlab.com/api" | ||
|
||
export class TestCredential { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: This is more of a LabClient than a TestCredential
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
makes sense, I can rename
const testEnv = envResponse[0]; | ||
if (testEnv.upn) { | ||
username = testEnv.upn; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If lab response doesn't contain upn, maybe log and throw?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm going to enhance some of these test utilities in a future PR. for now just getting e2e working.
await page.waitForNavigation({ waitUntil: "networkidle0"}); | ||
await takeScreenshot(page, testName, `loginPage`); | ||
await page.type("#i0116", username); | ||
await page.click("#idSIButton9"); | ||
await page.waitForNavigation({ waitUntil: "networkidle0"}); | ||
await takeScreenshot(page, testName, `pwdInputPage`); | ||
await page.type("#i0118", accountPwd); | ||
await page.click("#idSIButton9"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1
let username = ""; | ||
let accountPwd = ""; | ||
|
||
function setupScreenshotDir() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This has my high level approval, if there are specific pieces you want feedback on, please tag them
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM as comments will be addressed in future PRs.
This PR adds an updated end-to-end test framework as well as an updated CLI for samples. It also adds end-to-end tests to the lerna commands as well as to the build pipeline.