Giter VIP home page Giter VIP logo

Comments (18)

neonstalwart avatar neonstalwart commented on May 28, 2024

it sounds like an issue with the document used by vdom/create-element. it has a way to explicitly provide a document but ideally, mercury.app should be changed to take options that can be passed to main-loop so they can be passed to create-element and then you could do:

mercury.app(div, new component().state, component.render, { document: global.document });

from mercury.

neonstalwart avatar neonstalwart commented on May 28, 2024

if you wanted to check that this would fix your problem, you could try inlining mercury.app and passing the options to mercury.main yourself

document.body.appendChild(div);
mercury.Delegator();
var observ = new component().state;
var loop = mercury.main(observ, component.render, { document: global.document });
observ(loop.update);
div.appendChild(loop.target);

from mercury.

neonstalwart avatar neonstalwart commented on May 28, 2024

ad169d4 now allows you to pass options so if you update to use master you can try with the one liner:

mercury.app(div, new component().state, component.render, { document: global.document });

from mercury.

Raynos avatar Raynos commented on May 28, 2024

So when using mercury in node, loop.target is an instanceof of min-document.

vdom allows you to pass in which document you want with { document: doc }. By default it will use the global window.document in the browser and use min-document in node.

I actually recommend testing with min-document rather then testing with jsdom but your milage may vary.

See https://github.com/Raynos/dom-delegator/blob/master/test/dom-add-event.js as an example of tests.

The advantage of this approach is that the same test file will run verbatim in the browser and in node.

from mercury.

Raynos avatar Raynos commented on May 28, 2024

also note that the way we get the document in node is based on https://github.com/Raynos/global/blob/master/document.js#L5-L7

Which means if you re-order your code to be

var jsdom = require('jsdom').jsdom;

describe('...', function() {
  beforeEach(function(done) {
    var doc = jsdom('<html><body></body></html>');
    global.window = doc.parentWindow;
    global.document = window.document;
    var mercury = require('mercury');
    global.navigator = window.navigator;
    global.$ = undefined;
    jsdom.jQueryify(doc.parentWindow, "../../../bower_components/jquery/dist/jquery.js", function () {
      done();
    });
  });

i.e. require mercury after you set the global document, then mercury should respect your choice of global document.

from mercury.

neonstalwart avatar neonstalwart commented on May 28, 2024

require mercury after you set the global document, then mercury should respect your choice of global document.

@Raynos won't it cache the first one? which would make the first test right but the following tests wrong

from mercury.

Raynos avatar Raynos commented on May 28, 2024

@neonstalwart yes it will make the others wrong your right.

Because he uses a beforeEach. So ignore my comment about the order of require's. It's best you pass the document you want use to mercury.app()

from mercury.

avh4 avatar avh4 commented on May 28, 2024

I am very happy to hear this discussion, since react's reliance on global state and brittle initialization order (and the impression that the react devs don't seem to think it's a problem worth fixing) is the main reason I was driven to look for alternatives (and thus found mercury).

I'll be giving the suggestions a try later today. Thanks!

As for min-document vs jsdom, the purpose of the jsdom tests is to integration test some of the UI behavior (filling input fields, clicking buttons, etc). Does min-document provide a way to simulate DOM events? (I'll guess I'll be finding out.) For tests that don't need to cover UI interactions, I'm planning to just unit test the render methods and jsdom won't be needed for those tests.

from mercury.

Raynos avatar Raynos commented on May 28, 2024

@avh4 I maintain a fork of https://github.com/Raynos/synthetic-dom-events to do event based testing.

I used this helper ( https://github.com/Raynos/dom-delegator/blob/master/test/lib/create-event.js ) to create events.

Seems to work for the stuff i've tested but it might not be sufficient.

If you look at the commit history of min-document ( https://github.com/Raynos/min-document/commits/master ) you basically see me add features as an when I need them based on how complicated / involved my unit tests are.

from mercury.

avh4 avatar avh4 commented on May 28, 2024

I started looking at min-document + synthetic-dom-event first, and it's looking good... There are a few missing pieces.

First, calling dispatchEvent(ev) on a min-document node doesn't do anything, since there seem to be no listeners attached. From starting to read the source, it seems that mercury.Delegator() is used to somehow hook in emitters without using dom element listeners? So I guess I have to activate the delegator in my test somehow?

Second, I'm going to want a way to find a dom node by selector. I can use cheerio if I'm simply inspecting the rendered result, but if I want to trigger an event I'll need the dom node instance itself, which cheerio can't provide. Is there some light jquery-like library library I should know about that might work w/ min-document?

from mercury.

Raynos avatar Raynos commented on May 28, 2024

@avh4 the way mercury works is that calling mercury.app() will create a Delegator. I guess you have to pass the correct document into the Delegator

dom-delegator is currently hard coded, this should be fixed.

The second part is something that hasn't been build yet. I can add getElementsByClassName if that's sufficient for your needs.

from mercury.

Raynos avatar Raynos commented on May 28, 2024

@avh4 we now pass opts from mercury.app() directly to dom-delegator so it should respect your choice of document.

If it still doesn't work please add a minimal reproduction case and i'll add it as an integration test to mercury.

from mercury.

avh4 avatar avh4 commented on May 28, 2024

I updated to mercury#master and passed in the document, but no immediate luck. Maybe I'll have some more insight after reading a bit more about mercury.Delegator. Here's a minimal version of what I'm hoping to see working:

    var mercury = require('mercury');
    var h = mercury.h;
    var event = require('synthetic-dom-events');
    var document = require('min-document');

    var callCount = 0;

    var click = mercury.input(['click']).click;
    click(function() { callCount++; });
    function render(onClick) {
      return h('button', {'ev-click': mercury.event(onClick)}, 'Click Me');
    };

    div = document.createElement('div');
    mercury.app(div, mercury.value(click), render, {document: document});

    // action
    div.childNodes[0].dispatchEvent(event('click', {bubbles: true}));  // not sure what bubbles:true is for, but I saw it in your test helper mentioned above

    // assert
    expect(callCount).to.equal(1);

from mercury.

Raynos avatar Raynos commented on May 28, 2024

@avh4 you forgot document.body.appendChild(div)

dom-delegator adds listeners to the root. a DOM element must be in the document, i.e. a child of document.documentElement or a child of document.body for the events to work.

from mercury.

Raynos avatar Raynos commented on May 28, 2024

@avh4 see https://github.com/Raynos/mercury/blob/master/test/synthetic-events.js

from mercury.

Raynos avatar Raynos commented on May 28, 2024

@avh4 btw there is #virtualdom on IRC on freenode :) for more realtime collaboration ;)

from mercury.

avh4 avatar avh4 commented on May 28, 2024

Great! Got it working with min-document. In addition to adding the appendChild, I also had to let the event queue drain since the DOM appears to update asynchronously after the event fires.

It still doesn't fire the event in my jsdom attempt, but I'm not going to dig into that now.

from mercury.

Raynos avatar Raynos commented on May 28, 2024

@avh4

If you want to paste a jsdom reproduction case I can also test that out.

from mercury.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.