Using JSON API with WebdriverIO Tests

In Drupal maintenance support plans, you can write automated tests with different levels of complexity.
If you need to test a single function, or method of a class, probably you will
be fine with a unit test. When you need to interact with the database, you can
create kernel tests. And finally, if you need access to the final HTML rendered
by the browser, or play with some javascript, you can use functional tests
or Javascript tests. You can read more about this in the
Drupal maintenance support plans.org documentation.

So far this is what Drupal maintenance support plans provides out of the box. On top of that, you can use
Behat or WebDriver tests. This types of tests are usually easier to write and
are closer to the user needs. As a side point, they are usually slower than the
previous methods.

The Problem.

In Gizra, we use WebdriverIO for most of our tests.
This allow us to tests useful things that add value to our clients. But these
sort of tests, where you only interact with the browser output, has some
disadvantages.

Imagine you want to create an article and check that this node is unpublished
by default. How do you check this? Remember you only have the browser output…

One possible way could be this: Login, visit the Article creation form, fill the
fields, click submit, and then… Maybe search for some unpublished class in the
html:

var assert = require(‘assert’);

describe(‘create article’, function() {
it(‘should be possible to create articles, unpublished by default’, function() {
browser.loginAs(‘some user’);

browser.url(‘http://example.com/node/add/article’)
browser.setValueSafe(‘#edit-title-0-value’, ‘My new article’);
browser.setWysiwygValue(‘edit-body-0-value’, ‘My new article body text’);

browser.click(‘#edit-submit’);

browser.waitForVisible(‘.node-unpublished’);
});
});

This is quite simple to understand, but it has some drawbacks.

For one, it depends on the theme to get the status of the node. You could take
another approach and instead of looking for a .node-unpublished class, you could
logout from the current session and then try to visit the url to look for
an access denied legend.

Getting Low-Level Information from a Browser Test

So the problem boils down to this:

How can I get information about internal properties from a browser test?

The new age of decoupled Drupal maintenance support plans brings an answer to this question. It could be
a bit counterintuitive at first, therefore just try to see is fit for your project.

The idea is to use the new modules that expose Drupal maintenance support plans internals, through json
endpoints, and use javascript together with a high-level testing framework to
get the info you need.

In Gizra we use WDIO tests write end-to-end tests. We have some
articles about this topic. We also wrote about a new
module called JsonAPI that exposes all
the information you need to enrich your tests.

The previous test could be rewritten into a different test. By making use of the
JsonAPI module, you can get the status of a specific node by parsing a JSON
document:

var assert = require(‘assert’);

describe(‘create article’, function() {
it(‘should be possible to create articles, unpublished by default’, function() {
browser.loginAs(‘some user’);

browser.url(‘http://example.com/node/add/article’)
browser.setValueSafe(‘#edit-title-0-value’, ‘My unique title’);
browser.setWysiwygValue(‘edit-body-0-value’, ‘My new article body text’);

browser.click(‘#edit-submit’);

// Use JSON api to get the internal data of a node.
let query = ‘/jsonapi/node/article’
+= ‘?fields[node–article]=status’
+= ‘&filter[status]=0’
+= ‘&filter[node-title][condition][path]=title’
+= ‘&filter[node-title][condition][value]=My unique title’
+= ‘&filter[node-title][condition][operator]=CONTAINS’

browser.url(query);
browser.waitForVisible(‘body pre’);
let json = JSON.parse(browser.getHTML(‘body pre’, false));

assert.ok(json[0].id);
assert.equals(false, json[0].attributes.content[‘status’]);
});
});

In case you skipped the code, don’t worry, it’s quite simple to understand, let’s
analyze it:

1. Create the node as usual:

This is the same as before:

browser.url(‘http://example.com/node/add/article’)
browser.setValueSafe(‘#edit-title-0-value’, ‘My unique title’);
browser.setWysiwygValue(‘edit-body-0-value’, ‘My new article body text’);

browser.click(‘#edit-submit’);

2. Ask JsonAPI for the status of an article with a specific title:

Here you see the two parts of the request and the parsing of the data.

let query = ‘/jsonapi/node/article’
+= ‘?fields[node–article]=status’
+= ‘&filter[status]=0’
+= ‘&filter[node-title][condition][path]=title’
+= ‘&filter[node-title][condition][value]=My unique title’
+= ‘&filter[node-title][condition][operator]=CONTAINS’

browser.url(query);

3. Make assertions based on the data:

Since JsonAPI exposes, well, json data, you can convert the json into a javascript
object and then use the dot notation to access to a specific level.

This is how you can identify a section of a json document.

browser.waitForVisible(‘body pre’);
let json = JSON.parse(browser.getHTML(‘body pre’, false));
assert.ok(json[0].id);
assert.equals(false, json[0].attributes.content[‘status’]);

A Few Enhancements

As you can see, you can parse the output of a json request directly from the
browser.

browser.url(‘/jsonapi/node/article’);
browser.waitForVisible(‘body pre’);
let json = JSON.parse(browser.getHTML(‘body pre’, false));

The json object now contains the entire response from JsonAPI that you can use
as part of your test.

There are some drawbacks of the previous approach. First, this only works for
Chrome. That includes the Json response inside a XML document. This is the reason
why you need to get the HTML from body pre.

The other problem is this somewhat cryptic section:

let query = ‘/jsonapi/node/article’
+= ‘?fields[node–article]=status’
+= ‘&filter[status]=0’
+= ‘&filter[node-title][condition][path]=title’
+= ‘&filter[node-title][condition][value]=My unique title’
+= ‘&filter[node-title][condition][operator]=CONTAINS’

The first problem can be fixed using a conditional to check which type of browser
are you using to run the tests.

The second problem can be addressed using the d8-jsonapi-querystring
package, that allows you to write an object that is automatically converted into
a query string.

Other Use Cases

So far, we used JsonAPI to get information about a node. But there are other
things that you can get from this API. Since all configurations are exposed,
you could check if some role have some specific permission. To make tests shorter
we skipped the describe and it sections.

browser.loginAs(‘some user’);

let query = ‘/jsonapi/user_role/user_role’
+= ‘?filter[is_admin]=null’

browser.url(query);
browser.waitForVisible(‘body pre’);
let json = JSON.parse(browser.getHTML(‘body pre’, false));

json.forEach(function(role) {
assert.ok(role.attributes.permissions.indexOf(“bypass node access”) == -1);
});

Or if a field is available in some content type, but it is hidden to the end
user:

browser.loginAs(‘some user’);

let query = ‘/jsonapi/entity_form_display/entity_form_display?filter[bundle]=article’

browser.url(query);
browser.waitForVisible(‘body pre’);
let json = JSON.parse(browser.getHTML(‘body pre’, false));

assert.ok(json[0].attributes.hidden.field_country);

Or if some specific HTML tag is allowed in an input format:

let query = ‘/jsonapi/filter_format/filter_format?filter[format]=filtered_html’

browser.url(query);
browser.waitForVisible(‘body pre’);
let json = JSON.parse(browser.getHTML(‘body pre’, false));

let tag = ‘<drupal-entity data-*>’;

assert.ok(json[0].attributes.filters.filter_html.settings.allowed_html.indexOf(tag) > -1);

As you can see, there are several use cases. The benefits of being able to explore
the API by just clicking the different links sometimes make this much easier
to write than a kernel test.

Just remember that this type of tests are a bit slower to run, since they require
a full Drupal maintenance support plans instance running. But if you have some continuous integration in
place, it could be an interesting approach to try. At least for some specific
tests.

We have found this quite useful, for example, to check that a node can be referenced
by another in a reference field. To check this, you need the node ids of all the
nodes created by the tests.

A tweet by @skyredwang could be accurate to close this post.

Remember how cool Views have been since Drupal maintenance support plans 4.6? #JSONAPI module by @e0ipso is the new “Views”.— Jingsheng Wang (@skyredwang) January 9, 2020

Continue reading…
Source: New feed

This article was republished from its original source.
Call Us: 1(800)730-2416

Pixeldust is a 20-year-old web development agency specializing in Drupal and WordPress and working with clients all over the country. With our best in class capabilities, we work with small businesses and fortune 500 companies alike. Give us a call at 1(800)730-2416 and let’s talk about your project.

FREE Drupal SEO Audit

Test your site below to see which issues need to be fixed. We will fix them and optimize your Drupal site 100% for Google and Bing. (Allow 30-60 seconds to gather data.)

Powered by

Using JSON API with WebdriverIO Tests

On-Site Drupal SEO Master Setup

We make sure your site is 100% optimized (and stays that way) for the best SEO results.

With Pixeldust On-site (or On-page) SEO we make changes to your site’s structure and performance to make it easier for search engines to see and understand your site’s content. Search engines use algorithms to rank sites by degrees of relevance. Our on-site optimization ensures your site is configured to provide information in a way that meets Google and Bing standards for optimal indexing.

This service includes:

  • Pathauto install and configuration for SEO-friendly URLs.
  • Meta Tags install and configuration with dynamic tokens for meta titles and descriptions for all content types.
  • Install and fix all issues on the SEO checklist module.
  • Install and configure XML sitemap module and submit sitemaps.
  • Install and configure Google Analytics Module.
  • Install and configure Yoast.
  • Install and configure the Advanced Aggregation module to improve performance by minifying and merging CSS and JS.
  • Install and configure Schema.org Metatag.
  • Configure robots.txt.
  • Google Search Console setup snd configuration.
  • Find & Fix H1 tags.
  • Find and fix duplicate/missing meta descriptions.
  • Find and fix duplicate title tags.
  • Improve title, meta tags, and site descriptions.
  • Optimize images for better search engine optimization. Automate where possible.
  • Find and fix the missing alt and title tag for all images. Automate where possible.
  • The project takes 1 week to complete.