ember-cli-page-object icon indicating copy to clipboard operation
ember-cli-page-object copied to clipboard

Add a reasonable way to get DOM elements from page-objects

Open NullVoxPopuli opened this issue 5 years ago • 21 comments

Supersedes: https://github.com/san650/ember-cli-page-object/issues/473 As mentioned here: https://github.com/san650/ember-cli-page-object/pull/467#issuecomment-550490384

there are other APIs in progress, but they seem very verbose.

Ideally, from a testing perspective we wouldn't need any additional imports:

myPage.object.with.nested.things.dom

that dom getter would be present on all page objects, regardless of single or multiple, so that we have a single, consistent API for use with qunit-dom

thoughts?

/cc @ro0gr, @turbo87

NullVoxPopuli avatar Jan 07 '20 17:01 NullVoxPopuli

@NullVoxPopuli I believe, exposing an under-the-hood DOM element is a violation of the basic page object idea to abstract an implementation from the test. Typically when you change implemetation, you just want to update related page object, but all the related tests untouched, and that's one of the goals of the page objects.

As far as I can see, most of the qunit-dom helpers are tightly coupled to the dom(obviously), which makes them a bad choice to be integrated with page objects(imo).

ro0gr avatar Jan 11 '20 21:01 ro0gr

then ember-cli-page-object needs assertions.: -\

as is, doing assert.equal(page.thing, 'value'), is super unhelpful if something goes wrong. we need better error messages.

Like, expected the attribute [thing] to have value of 'value'

NullVoxPopuli avatar Jan 11 '20 21:01 NullVoxPopuli

Yes, it does, but "qunit-dom" still doesn't seem to be a solution. Let's assume, you have:

const page = create({
  hasSomeState: hasClass('someState')
})

"qunit-dom" would not allow us to use this hasSomeState page object prop, and we would need to use hasClass from the "qunit-dom" to get some contextual message, which uncovers the same issue of exposing implementation details.

ro0gr avatar Jan 11 '20 21:01 ro0gr

then, it may be easiest, philosophically, to implement a:

assert.pageObject(page.hasSomeState)

so that way, we could have an error message like:

Expected [selector] to have class 'someState', but instead had [list of classes]

NullVoxPopuli avatar Jan 11 '20 21:01 NullVoxPopuli

Exactly!

A while ago I've made a quick poc for this https://github.com/ro0gr/ember-qunit-page-object, and in general, this direction looks promising to me. Unfortunately I still don't have enough time to renew my efforts there, but we made a step on the that direction some time ago. In ec-page-object, we now have getPageObjectDefinition private API, which can be used to get of the original definition and build assertions API on the fly for each specific page object.

ro0gr avatar Jan 11 '20 21:01 ro0gr

I just found this: https://github.com/ro0gr/ember-qunit-page-object/blob/master/tests/smoke-test.js

all of that is very similar to qunit-dom, but requires all the assertions to be wrapped in an arrow function provided to .as() :-\

NullVoxPopuli avatar Jan 11 '20 22:01 NullVoxPopuli

requires all the assertions to be wrapped in an arrow function provided to .as()

I don't think as should be required

ro0gr avatar Jan 11 '20 22:01 ro0gr

I think it was just a single test, but you can find another tests w/o as there https://github.com/ro0gr/ember-qunit-page-object/blob/d17d2e60a37612acd99f86589f1ac500a7a0f473/tests/smoke-test.js#L63-L67

ro0gr avatar Jan 11 '20 22:01 ro0gr

what about integrating with qunit-dom?

assert.dom could be altered to take a page object, it could read the getPageObjectDefinition on the page object property, and then we already have all the assertion work done for us? :D

assert.dom(page.object.subObject).hasText('some text');

I think this is doable if getPageObjectDefinition allows access to a selector (non-jquery selector) or element

NullVoxPopuli avatar Jan 11 '20 22:01 NullVoxPopuli

I'd like to delegate that assertions api somewhere, but

if getPageObjectDefinition allows access to a selector (non-jquery selector) or element

I think it isn't achievable via a single CSS selector string. For example, there is no reliable way to get a nested collection element via single CSS selector. The best I can think of is some kind of query DSL object, which would contain nested scope and at pairs.

Also, I'm not sure if the knowledge about the page objects should be a "qunit-dom" responsibility 🤔

ro0gr avatar Jan 11 '20 22:01 ro0gr

For example, there is no reliable way to get a nested collection element via single CSS selector.

that's all qunit-dom needs. the page object can provide the element or collection.

Also, I'm not sure if the knowledge about the page objects should be a "qunit-dom" responsibility 🤔

I think it's better than re-inventing qunit-dom for page objects? less to maintain overall, imo

NullVoxPopuli avatar Jan 11 '20 22:01 NullVoxPopuli

I'd say, it gets inspiration from qunit-dom(pushResult() and Qunit.extend()), but it doesn't re-invent something.

FWIW, I think, you can achieve .dom for each page object by decorating create from the page object, so you can extend the base DSL.

ro0gr avatar Jan 12 '20 21:01 ro0gr

@ro0gr what if under the hood of assert.po we just do smth like this

QUnit.assert.po(pageObject) {
  return this.dom(pageObject.element);
}

yratanov avatar Jan 20 '20 03:01 yratanov

@yratanov I think this is a perfect answer to a question "how to integrate", with that we don't even need to expose element from the page objects:

QUnit.assert.po(pageObject) {
  return this.dom(findOne(pageObject));
}

However, in scale, integration of these 2 libs has a number of pitfalls, like:

  • inability to support custom properties
  • Leaking DOM knowledge to a test, which can lead to mixed styles even in a single test

ro0gr avatar Jan 21 '20 02:01 ro0gr

@ro0gr yep, I think you are right. Can I be any help with https://github.com/ro0gr/ember-qunit-page-object?

yratanov avatar Jan 21 '20 02:01 yratanov

@yratanov thanks! Glad to see you are interested. As far as I remember, there were some complexity in parsing page object instance shape(props) due to a lack of getPageObjectDefinition those days. Also some experimentation has to be done to figure out an effective way to build assertions(including negations, like hasSomething, not.hasSomething).

I'll try to renew my mind about this addon the next few days and create some tickets, in order to have some plan.

ro0gr avatar Jan 21 '20 20:01 ro0gr

@NullVoxPopuli what do you think? is the snippet, suggested by @yratanov, something you are looking for?

ro0gr avatar Jan 21 '20 20:01 ro0gr

maybe! would need to see it in action to really know what the implications are

NullVoxPopuli avatar Jan 21 '20 22:01 NullVoxPopuli

@NullVoxPopuli @ro0gr I've created a small addon for it https://github.com/yratanov/ember-page-object-asserts . It's very simple, my main goal was to make errors more descriptive. API has something in common with qunit-dom.

const page = create({
  link: {
    scope: 'a',
    href: attribute('href'),
    isHighlighted: hasClass('highlighted'),
  },
  list: collection('li'),
  input: { scope: 'input' }
});

assert.po(page.link).hasText("test");
assert.po(page.link).hasNoText("bla");
assert.po(page.link).hasText(/test/);
assert.po(page.link).has('href', 'google.com');
assert.po(page.link).has('isHighlighted');
assert.po(page.input).hasValue('test');
assert.po(page.input).isPresent();
assert.po(page.input).isHidden();
assert.po(page.list).hasItems(2);

Please tell me what you think :)

It's my first addon, so I might be messed something :)

yratanov avatar Feb 15 '20 08:02 yratanov

made few improvements to the addon, now you can do this:


const page = create({
  link: {
    scope: 'a',
    href: attribute('href'),
    isHighlighted: hasClass('highlighted'),
  }
});

assert.po(page.link).href('google.com');
assert.po(page.link).isHighlighted();

Directly calling props as methods :)

yratanov avatar Feb 16 '20 04:02 yratanov

@yratanov I like it!

Since this issue seems to be a bit unrelated to a custom assertions API, left some initial feedback at your addon repo https://github.com/yratanov/ember-page-object-asserts/issues/1

ro0gr avatar Feb 16 '20 16:02 ro0gr