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

Get Nodejs to recognise jquery command for publishButton jest test file #764

Closed

Conversation

NARUDESIGNS
Copy link
Collaborator

Make sure these boxes are checked before your pull request (PR) is ready to be reviewed and merged. Thanks!

  • tests pass -- look for a green checkbox ✔️ a few minutes after opening your PR -- or run tests locally with grunt jasmine
  • code is in uniquely-named feature branch and has no merge conflicts
  • PR is descriptively titled
  • PR body includes fixes #0000-style reference to original issue #
  • ask @publiclab/reviewers for help, in a comment below

We're happy to help you get this ready -- don't be afraid to ask for help, and don't be discouraged if your tests fail at first!

If tests do fail, click on the red X to learn why by reading the logs.

Please be sure you've reviewed our contribution guidelines at https://publiclab.org/contributing-to-public-lab-software

We have a loose schedule of reviewing and pulling in changes every Tuesday and Friday, and publishing changes on Fridays.

Thanks!

@gitpod-io
Copy link

gitpod-io bot commented Dec 13, 2021

@NARUDESIGNS
Copy link
Collaborator Author

I noticed that node throws an error "$ is not defined" because jquery requires a window object. To fix this, I did:

   const {JSDOM} = require("jsdom");
   const myJSDom = new JSDOM(fs.readFileSync(path));
   $ = require('jquery')(myJSDom.window);

The first line requires jsdom which I think is already installed in the PublicLab.Editor project.

The second line in the snippet above reads the example/index.html file from the template you had wrote for all new jest test files:

path = fs.realpathSync('file://../examples/index.html');

The third line gets $ to point to the example/index.html file so we can do something like

// get the button text value
console.log($('.ple-publish').text());

Let me know your comments on how we can progress from here @jywarren

@jywarren
Copy link
Member

This looks excellent, and if the test properly fails, that's a great sign. If you can fix the test and get it to turn green, then that's a full proof of concept and we could merge this!

I think the next steps would be to look at what we would need to add to each test file so that the rest of the Jasmine -> Jest test conversions will go smoothly. Ideally we can write this out in #743 so that we can make some of these into FTO issues for others to follow -- what do you think?

Or, you could make "empty" Jest test files for each Jasmine file, and the FTOs would be copying in and adjusting the Jasmine tests but not having to do the file creation. That way you could include these lines at the top of each file and newcomers wouldn't have to worry about them. What do you prefer?

@NARUDESIGNS
Copy link
Collaborator Author

NARUDESIGNS commented Dec 13, 2021

I think the next steps would be to look at what we would need to add to each test file so that the rest of the Jasmine -> Jest test conversions will go smoothly. Ideally, we can write this out in #743 so that we can make some of these into FTO issues for others to follow -- what do you think?

I agree, I think this next step will be a lot easier after getting the tests to pass. But I got questions about the test case for the publish button. I'd reach out on the channel tomorrow morning.
@jywarren


test('something we are testing described here', () => {
// Check initially that Publish button is disabled.
expect($('.ple-publish').prop('disabled')).toBe(true);
Copy link
Member

Choose a reason for hiding this comment

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

OK this is what's failing now. And it looks like a real failure - but is it? In theory, the editor's Publish button should really be disabled on initial page load, right? because it's waiting for you to input a title and some text before it thinks you should be able to press Publish.

Maybe we should start by checking something more basic, like this?

expect($('.ple-publish')).toBeDefined();

That way we know we're looking at the correct page at least, then we can try to figure out why the button is not disabled. How does that sound?

Copy link
Member

Choose a reason for hiding this comment

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

I'm working from this list of Jest assertions: https://jestjs.io/docs/using-matchers

Copy link
Member

Choose a reason for hiding this comment

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

Ah, i see. From your gitter chat comment, you're saying the button gets created, but validation is never run (_editor.validate()), so it never adds the disabled state to the button because it never checks if you've added a title.

That would be good, in that we are reading the actual HTML. But why isn't it running validation? Normally these lines should "boot up" the editor including running initial validations:

(function () {
editor = new PL.Editor({
textarea: $(".ple-textarea")[0],
destination: "/notes/create",
mapModule: true,
format: "publiclab",
lat: 23,
lon: 77,
zoom: 5,
});

And after all, the test file this one is based on does the exact same thing - and relies on that Editor "boot-up" to have run: https://github.com/publiclab/PublicLab.Editor/blob/main/spec/javascripts/button_spec.js

How can we see the errors that may occur preventing that bootup from happening? When we look through the log in this PR, are there signs that some code hit an error or did not run?

Earlier tests seem to have run. Did they load the page properly?https://github.com/publiclab/PublicLab.Editor/runs/4510360996?check_suite_focus=true#step:7:8

Hmm, a lot of them seem to be asynchronous, meaning they're waiting for other stuff to complete before trying to run. Do we need to do the same for this new test?

test('Add Custom Insert text in rich text mode', async () => {
if (await page.evaluate(() => $(".woofmark-mode-markdown").is(":disabled"))) {
await page.click('.woofmark-mode-wysiwyg');
}
await page.waitForSelector('.ple-module-body');

Copy link
Member

Choose a reason for hiding this comment

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

So would that be like this, plus adding async to the top of the containing function?

Suggested change
expect($('.ple-publish').prop('disabled')).toBe(true);
await expect($('.ple-publish').prop('disabled')).toBe(true);

@NARUDESIGNS
Copy link
Collaborator Author

NARUDESIGNS commented Dec 18, 2021

@jywarren I see the problem now.
Running scripts via jsdom is disabled by default. See jsdom repo
To run scripts, a second argument is passed to the jsdom constructor. This argument looks like this

{
    runScripts: "dangerously",
    resources: "usable"
}

When I add this, I notice it tries to run the scripts but then the google map script throws an error saying the browser (jsdom browser environment I think) is not supported

Screenshot 2021-12-18 at 16 10 54

@jywarren
Copy link
Member

Aha - well that's very good progress! So there are other ways to run a browser environment, and puppeteer actually uses full browsers run on the commandline, like chrome (sort of strangely called headless-chrome since it has no graphical user interface). And I think this is what Jest had been configured for - can we try switching from jsdom (which really more like simulates a browser JS environment) to a full "headless" browser?

@jywarren
Copy link
Member

So i think by loading in jsdom, we are creating a secondary browser environment, and the default Jest is set up with is puppeteer already.

I was reading this page and it made some sense... https://github.com/smooth-code/jest-puppeteer/blob/master/packages/jest-environment-puppeteer/README.md

Or maybe https://stackoverflow.com/a/46987959/1116657 is a good guide.

This is starting to look more like what i had tried in #749 but honestly i got so turned around in that issue i bet it's not even very useful -- better to just start fresh.

test('something we are testing described here', () => {
var $;
beforeAll(async () => {
path = fs.realpathSync('file://../examples/index.html');
Copy link
Member

Choose a reason for hiding this comment

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

I'm not 100% sure here, but working from https://stackoverflow.com/a/46987959/1116657 I'm thinking we should try something like this:

Suggested change
path = fs.realpathSync('file://../examples/index.html');
import { launch } from 'puppeteer'
(async () => {
const browser = await launch({headless: false});
const page = await browser.newPage();
await page.goto('file://../examples/index.html', {waitUntil: 'networkidle'});
//path = fs.realpathSync('file://../examples/index.html');
await page.addScriptTag({url: 'https://code.jquery.com/jquery-3.2.1.min.js'});
await page.waitForNavigation()

My main uncertainty is how to load the local file rather than a remote URL. Not sure what I wrote here will work.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yea exactly, I bumped into this as well since I decided I could no longer make use of jsdom. I tried this but it didn't work for me.
I think we might be able to load the local version of jquery using:

await page.addScriptTag({path: require.resolve('jquery')})

but I wasn't sure what that path (path to jquery) is for our project. So I did

const jqueryPath = require('jquery')

then I hovered on 'jquery' and saw the path, I copied it and used it directly. Here's the new error I got:

Screenshot 2021-12-19 at 19 17 08

I'm not so sure what the '_productName' is but I'm still looking. Do you have any idea what it is?
@jywarren

@jywarren
Copy link
Member

But then i wonder - can we just do exactly what's in this test, where we run stuff in the page using evaluate(), then use expect() to measure what we get back?

// Evaluate the expression
const stringIsIncluded2 = await page.evaluate(() => document.querySelector('.ple-textarea').value.includes('[notes:tag]'));
expect(stringIsIncluded2).toBe(true);

@jywarren
Copy link
Member

jywarren commented Dec 19, 2021 via email

@jywarren
Copy link
Member

jywarren commented Dec 19, 2021 via email

@NARUDESIGNS
Copy link
Collaborator Author

Does that make sense?

@jywarren yes it does. In fact, I had to wrap the code in a try...catch block so I can catch and log the errors but I got the same error. I could see where _productName was used in a puppeteer.js file but I'm not sure what it expects or what exactly it is. I have to look more into it.

@jywarren
Copy link
Member

Ah ok - can you point me to the line in puppeteer? Whatever _____._productName is attached to is returning nil. Maybe we can search the Puppeteer issues for similar errors...

@jywarren
Copy link
Member

Aha - maybe this will work: puppeteer/puppeteer#6266 (comment)

@jywarren
Copy link
Member

I'm trying out the theory of "let's just use non-jQuery to reproduce this in Jest following the format in other Jest tests" idea in #767

Let's see how it does!

@jywarren
Copy link
Member

jywarren commented Jan 4, 2022

OK, so let's close this up i think, just to keep things tidy? Thanks!

@jywarren jywarren closed this Jan 4, 2022
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.

2 participants