Skip to content
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

Add integration test for staging env w/ Puppeteer #843

Merged
merged 5 commits into from
Oct 14, 2019

Conversation

LeoSL
Copy link
Contributor

@LeoSL LeoSL commented Oct 5, 2019

Pull request checklist

Make sure you:

Short description of the change(s)

Fix #810

  • Installs Puppeteer as a dev dependency in package.json.
  • Requests a collection of webhint.io staging URLs and saves the response in a
    Map() object.
  • Iterates over the Map and checks if is there any status different from 200 or
    another unknown error.
  • If there is an error, throws it to interrupt the test execution

🕹 How to test

  • Run the script node helpers/integration-tests.js

  • If you want to see the script finding an error you can add a bad URL to the URL collection.
    Example: http://pudim.com.br/xunda.jpg

@LeoSL LeoSL force-pushed the add-staging-integration-test branch from f4febc7 to 6c457a7 Compare October 5, 2019 17:43
.finally(() => {
if (index === (URLsToVerify.length - 1)) {
resolve(responses);
browser.close();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

browser.close() returns a Promise.
I'm thinking of 2 possibilities, if you have a better one please go for it:

  1. Add the condition after responses.set(). Although we might end up with a bit more nesting 🤔
  2. Use async/await inside a for..of and test the pages one by one. This might make the code a bit easier even if it means the test will take a few more seconds (which is fine TBH).

What do you think?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need to keep the responses in a Map.
As @molant says, you should use async/await inside a for..of and after each scan, print the status (that way we can see if it is failing more than one url) and after all the urls are scanned, throw and error if there was any exception (or maybe it is enough if we return an exitCode !== 0)

Copy link
Contributor

@sarvaje sarvaje left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, IMO, we should check that running a scan is working too.

.finally(() => {
if (index === (URLsToVerify.length - 1)) {
resolve(responses);
browser.close();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need to keep the responses in a Map.
As @molant says, you should use async/await inside a for..of and after each scan, print the status (that way we can see if it is failing more than one url) and after all the urls are scanned, throw and error if there was any exception (or maybe it is enough if we return an exitCode !== 0)

@LeoSL
Copy link
Contributor Author

LeoSL commented Oct 8, 2019

Also, IMO, we should check that running a scan is working too.

@sarvaje Can you please clarify what you mean by "check that running a scan is working"?

@sarvaje
Copy link
Contributor

sarvaje commented Oct 8, 2019

@sarvaje Can you please clarify what you mean by "check that running a scan is working"?

Sorry hehehe. I mean going to the /scanner and add some url e.g. https://example.com click on run scan and see if you get a status code 200.

Some times, everything looks good, but then when you scan an url, something is broken.

@molant
Copy link
Member

molant commented Oct 8, 2019

There are a couple methods in puppeteer that make this relatively easy:

  • page.type: it accepts a css selector and the text to type on the input
  • page.click which accepts a css selector and will "click" on it

Because we are going to navigate to a page we will probably have to use page.waitForNavigation to make sure that we navigate to a results page and get a 200 status code. The docs page has a good example on how to use waitForNavigation in combination with click and such but I think it will be something similar to:

await page.goto('/scanner/');
await page.type('selector for input', 'url to analyze');
const [result] = await Promise.all([
  page.waitForNavigation(),
  page.click('selector for button')
]);

// check result here

@LeoSL
Copy link
Contributor Author

LeoSL commented Oct 8, 2019

@molant I've rebased from upstream master and did the following:

  • Refactored the code to use async/await syntax sugar instead of Promise chains
  • Isolated the scanner test

Let me know if the changes sound good to you.
Thanks!

Copy link
Member

@molant molant left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good @LeoSL !
I just have one comment that I hope you can check for me. Otherwise this is almost done!

@@ -0,0 +1,53 @@
const puppeteer = require('puppeteer');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We no longer need this file 🙂

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I forgot that one! Thanks!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like this file is still in the PR

return new Promise((resolve) => {
let errorFound = false;

staticURLsToVerify.forEach(async (url, index) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe .forEach doesn't await so all the items in the array are called at the same time and thus starting multiple different instances of the browser. When testing this how many separate chrome windows did you see? Was it just one being opened and closed or several?

If you saw multiple instances then we should probably change this to something like this:

const runStaticTests = async () => {
    let errorFound = false;

    for (const url of staticURLsToVerify) {
         const resultStatus = await runPuppeteer(url);
        
        if (resultStatus !== 200) {
            errorFound = true;
        }
    }

    return errorFound;
}

Copy link
Contributor Author

@LeoSL LeoSL Oct 9, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@molant I'm running the Chrome headless version so I don't observe the windows popping up - thus I can't answer your question about the instances.

When running on the CLI they appear pretty much sequential on all my tests. I'm assuming that if they're being fired sequentially the printing (console.log) order would change on an ad hoc basis.

If you're strong about the for..of I can check it out later but I believe it would require a lot of other logic changes because I wouldn't have access to the index.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I suspected forEach doesn't await , I've been bitten by this in the past 😅

With the code I posted earlier you don't need access to the index. Because the urls are being analyzed sequentially, as soon as the for..of ends you can return errorFound. We also add the keyword async so no need to create a Promise object.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's great, thanks @molant
I will do the fixes later today! 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@molant Done!

- Installs Puppeteer as a dev dependency on package.json.
- Requests a collection of webhint.io staging URLs and saves the response in a
Map() object.
- Iterates over the Map and checks if is there any status different from 200 or
another unknown error.
- If there is any error, throws it to interrupt the test execution
- Also, run both static and scanner tests sequentially to a better console
logging experience
@LeoSL LeoSL force-pushed the add-staging-integration-test branch from 2e49c25 to 441db95 Compare October 10, 2019 20:40
@LeoSL
Copy link
Contributor Author

LeoSL commented Oct 11, 2019

Sorry, @molant forgot again to remove. Now I believe everything looks fine!

Copy link
Member

@molant molant left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great @LeoSL. Thanks a lot!

@sarvaje @antross can I get a second 👍 to merge this?

Copy link
Contributor

@sarvaje sarvaje left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just one NIT, but nothing blocking.

helpers/integration-tests/scanner.js Show resolved Hide resolved
@antross
Copy link
Member

antross commented Oct 14, 2019

@molant Looks like we two approvals now. Is there anything else you wanted or is this good to merge?

@molant
Copy link
Member

molant commented Oct 14, 2019 via email

@antross antross merged commit 0ae8573 into webhintio:master Oct 14, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Create integration test script
4 participants