{"id":72952,"date":"2023-04-26T09:01:19","date_gmt":"2023-04-26T09:01:19","guid":{"rendered":"https:\/\/www.cryptocabaret.com\/?p=72952"},"modified":"2023-04-26T09:01:19","modified_gmt":"2023-04-26T09:01:19","slug":"test-your-drupal-website-with-cypress","status":"publish","type":"post","link":"https:\/\/www.cryptocabaret.com\/?p=72952","title":{"rendered":"Test your Drupal website with Cypress"},"content":{"rendered":"<p><span class=\"field field--name-title field--type-string field--label-hidden\">Test your Drupal website with Cypress<\/span><br \/>\n<span class=\"field field--name-uid field--type-entity-reference field--label-hidden\"><a title=\"View user profile.\" href=\"https:\/\/opensource.com\/users\/cobadger\" class=\"username\">cobadger<\/a><\/span><br \/>\n<span class=\"field field--name-created field--type-created field--label-hidden\">Wed, 04\/26\/2023 &#8211; 03:00<\/span><\/p>\n<div class=\"clearfix text-formatted field field--name-body field--type-text-with-summary field--label-hidden field__item\">\n<p>If you don&#8217;t include tests in your Drupal development, chances are it&#8217;s because you think it adds complexity and expense without benefit. <a href=\"https:\/\/www.cypress.io\/\" target=\"_blank\" rel=\"noopener\">Cypress<\/a> is an open source tool with many benefits:<\/p>\n<ul>\n<li>Reliably tests anything that runs in a web browser<\/li>\n<li>Works on any web platform (it&#8217;s great for testing projects using front-end technologies like <a href=\"https:\/\/opensource.com\/article\/20\/11\/reactjs-tutorial\" target=\"_blank\" rel=\"noopener\">React<\/a>)<\/li>\n<li>Highly extensible<\/li>\n<li>Increasingly popular<\/li>\n<li>Easy to learn and implement<\/li>\n<li>Protects against regression as your projects become more complex<\/li>\n<li>Can make your development process more efficient<\/li>\n<\/ul>\n<p>This article covers three topics to help you start testing your Drupal project using Cypress:<\/p>\n<ol type=\"1\">\n<li><a href=\"https:\/\/opensource.com\/article\/23\/4\/website-test-drupal-cypress#install-cypress\">Installing Cypress<\/a><\/li>\n<li><a href=\"https:\/\/opensource.com\/article\/23\/4\/website-test-drupal-cypress#write-run\">Writing and running basic tests using Cypress<\/a><\/li>\n<li><a href=\"https:\/\/opensource.com\/article\/23\/4\/website-test-drupal-cypress#customize-cypress\">Customizing Cypress for Drupal<\/a><\/li>\n<\/ol>\n<h2>Install Cypress<\/h2>\n<p>For the purposes of this tutorial I&#8217;m assuming that you have built a local dev environment for your Drupal project using the `drupal\/recommended-project` project. Although details on creating such a project are outside of the scope of this piece, I recommend\u00a0<a data-saferedirecturl=\"https:\/\/www.google.com\/url?q=https:\/\/www.specbee.com\/blogs\/getting-started-with-lando-and-drupal-9&amp;source=gmail&amp;ust=1682166790617000&amp;usg=AOvVaw1yMfzaJ_OGC0TLLv57DNlz\" href=\"https:\/\/www.specbee.com\/blogs\/getting-started-with-lando-and-drupal-9\" target=\"_blank\" rel=\"noopener\">Getting Started with Lando and Drupal 9<\/a>.<\/p>\n<p>Your project has at least this basic structure:<\/p>\n<pre>\n<code class=\"language-bash\">vendor\/\nweb\/\n.editorconfig\n.gitattributes\ncomposer.json\ncomposer.lock<\/code><\/pre>\n<p>The cypress.io site has <a href=\"https:\/\/docs.cypress.io\/guides\/getting-started\/installing-cypress\" target=\"_blank\" rel=\"noopener\">complete installation instructions<\/a> for various environments. For this article, I installed Cypress using <a href=\"https:\/\/docs.npmjs.com\/downloading-and-installing-node-js-and-npm\" target=\"_blank\" rel=\"noopener\">npm<\/a>.<\/p>\n<p>Initialize your project using the command <code>npm init<\/code>. Answer the questions that Node.js asks you, and then you will have a <code>package.json<\/code> file that looks something like this:<\/p>\n<pre>\n<code class=\"language-javascript\">{\n  \"name\": \"cypress\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Installs Cypress in a test project.\",\n  \"main\": \"index.js\",\n  \"scripts\": {\n    \"test\": \"echo \"Error: no test specified\" &amp;&amp; exit 1\"\n  },\n  \"author\": \"\",\n  \"license\": \"ISC\"\n}<\/code><\/pre>\n<p>Install Cypress in your project:<\/p>\n<pre>\n<code class=\"language-bash\">$ npm install cypress --save-dev<\/code><\/pre>\n<p>Run Cypress for the first time:<\/p>\n<pre>\n<code class=\"language-bash\">$ npx cypress open<\/code><\/pre>\n<p>Because you haven&#8217;t added a config or any scaffolding files to Cypress, the Cypress app displays the welcome screen to help you configure the project. To configure your project for E2E (end-to-end) testing, click the <strong>Not Configured<\/strong> button for E2E Testing. Cypress adds some files to your project:<\/p>\n<pre>\n<code class=\"language-bash\">cypress\/\nnode_modules\/\nvendor\/ \nweb\/\n.editorconfig\n.gitattributes\ncomposer.json\ncomposer.lock\ncypress.config.js\npackage-lock.json\npackage.json<\/code><\/pre>\n<p>Click <strong>Continue<\/strong> and choose your preferred browser for testing. Click <strong>Start E2E Testing in [your browser of choice]<\/strong>. I&#8217;m using a Chromium-based browser for this article.<\/p>\n<p>In a separate window, a browser opens to the <strong>Create your first spec<\/strong> page:<\/p>\n<article class=\"align-center media media--type-image media--view-mode-default\">\n<div class=\"field field--name-field-media-image field--type-image field--label-hidden field__item\">  <img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/opensource.com\/sites\/default\/files\/2023-04\/cypress-in-browser.webp\" width=\"1182\" height=\"656\" alt=\"Cypress in a web browser\"><\/div>\n<div class=\"field field--name-field-caption field--type-text-long field--label-hidden caption field__item\"><span class=\"caption__byline\">Image by: <\/span><\/p>\n<p>(Jordan Graham, CC BY-SA 4.0)<\/p>\n<\/div>\n<\/article>\n<p>Click on the <strong>Scaffold example specs<\/strong> button to create a couple of new folders with example specs to help you understand how to use Cypress. Read through these in your code editor, and you&#8217;ll likely find the language (based on JavaScript) intuitive and easy to follow.<\/p>\n<p>Click on <strong>any<\/strong> in the test browser. This reveals two panels. On the left, a text panel shows each step in the active spec. On the right, a simulated browser window shows the actual user experience as Cypress steps through the spec.<\/p>\n<p>Open the <code>cypress.config.js<\/code> file in your project root and change it as follows:<\/p>\n<pre>\n<code class=\"language-javascript\">const { defineConfig } = require(\"cypress\");\n \nmodule.exports = defineConfig({\n  component: {\n    fixturesFolder: \"cypress\/fixtures\",\n    integrationFolder: \"cypress\/integration\",\n    pluginsFile: \"cypress\/plugins\/index.js\",\n    screenshotsFolder: \"cypress\/screenshots\",\n    supportFile: \"cypress\/support\/e2e.js\",\n    videosFolder: \"cypress\/videos\",\n    viewportWidth: 1440,\n    viewportHeight: 900,\n  },\n\n  e2e: {\n    setupNodeEvents(on, config) {\n      \/\/ implement node event listeners here\n    },\n    baseUrl: \"https:\/\/[your-local-dev-url]\",\n    specPattern: \"cypress\/**\/*.{js,jsx,ts,tsx}\",\n    supportFile: \"cypress\/support\/e2e.js\",\n    fixturesFolder: \"cypress\/fixtures\"\n   },\n });<\/code><\/pre>\n<p>Change the <code>baseUrl<\/code> to your project&#8217;s URL in your local dev environment.<\/p>\n<p>These changes tell Cypress where to find its resources and how to find all of the specs in your project.<\/p>\n<h2>Write and run basic tests using Cypress<\/h2>\n<p>Create a new directory called <code>integration<\/code> in your <code>\/cypress<\/code> directory. Within the <code>integration<\/code> directory, create a file called <code>test.cy.js<\/code>:<\/p>\n<pre>\n<code class=\"language-bash\">cypress\/\n\u251c\u2500 e2e\/\n\u251c\u2500 fixtures\/\n\u251c\u2500 integration\/ \n\u2502  \u251c\u2500 test.cy.js\n\u251c\u2500 support\/ \nnode_modules\/\nvendor\/\nweb\/\n.editorconfig\n.gitattributes\ncomposer.json\ncomposer.lock\ncypress.config.js\npackage-lock.json\npackage.json<\/code><\/pre>\n<p>Add the following contents to your <code>test.cy.js<\/code> file:<\/p>\n<pre>\n<code class=\"language-javascript\">describe('Loads the front page', () =&gt; {\n  it('Loads the front page', () =&gt; {\n    cy.visit('\/')\n    cy.get('h1.page-title')\n      .should('exist')\n  });\n});\n \ndescribe('Tests logging in using an incorrect password', () =&gt; {\n  it('Fails authentication using incorrect login credentials', () =&gt; {\n    cy.visit('\/user\/login')\n    cy.get('#edit-name')\n      .type('Sir Lancelot of Camelot')\n    cy.get('#edit-pass')\n      .type('tacos')\n    cy.get('input#edit-submit')\n      .contains('Log in')\n      .click()\n    cy.contains('Unrecognized username or password.')\n  });\n});<\/code><\/pre>\n<\/p>\n<div class=\"callout-float-right embedded-resource-list\" data-analytics-region=\"sidebar\">\n<div class=\"field field--name-title field--type-string field--label-hidden field__item\">Our favorite resources about open source<\/div>\n<div class=\"field field--name-links field--type-link field--label-hidden field__items\">\n<div class=\"field__item\"><a href=\"https:\/\/opensource.com\/downloads\/cheat-sheet-git?intcmp=7016000000127cYAAQ\" data-analytics-category=\"resource list\" data-analytics-text=\"Git cheat sheet\">Git cheat sheet<\/a><\/div>\n<div class=\"field__item\"><a href=\"https:\/\/developers.redhat.com\/cheat-sheets\/advanced-linux-commands\/?intcmp=7016000000127cYAAQ\" data-analytics-category=\"resource list\" data-analytics-text=\"Advanced Linux commands cheat sheet\">Advanced Linux commands cheat sheet<\/a><\/div>\n<div class=\"field__item\"><a href=\"https:\/\/opensource.com\/tags\/alternatives?intcmp=7016000000127cYAAQ\" data-analytics-category=\"resource list\" data-analytics-text=\"Open source alternatives\">Open source alternatives<\/a><\/div>\n<div class=\"field__item\"><a href=\"https:\/\/www.redhat.com\/en\/services\/training\/rh024-red-hat-linux-technical-overview?intcmp=7016000000127cYAAQ\" data-analytics-category=\"resource list\" data-analytics-text=\"Free online course: RHEL technical overview\">Free online course: RHEL technical overview<\/a><\/div>\n<div class=\"field__item\"><a href=\"https:\/\/console.redhat.com\/?intcmp=7016000000127cYAAQ\" data-analytics-category=\"resource list\" data-analytics-text=\"Register for your free Red Hat account\">Register for your free Red Hat account<\/a><\/div>\n<div class=\"field__item\"><a href=\"https:\/\/opensource.com\/downloads\/cheat-sheets?intcmp=7016000000127cYAAQ\" data-analytics-category=\"resource list\" data-analytics-text=\"Check out more cheat sheets\">Check out more cheat sheets<\/a><\/div>\n<\/p><\/div>\n<\/p><\/div>\n<p>When you click on <code>test.cy.js<\/code> in the Cypress application, watch each test description on the left as Cypress performs the steps in each <code>describe()<\/code> section.<\/p>\n<p>This spec demonstrates how to tell Cypress to navigate your website, access HTML elements by ID, enter content into input elements, and submit the form. This process is how I discovered that I needed to add the assertion that the <code><\/code> element contains the text <strong>Log in<\/strong> before the input was clickable. Apparently, the flex styling of the submit input impeded Cypress&#8217; ability to &#8220;see&#8221; the input, so it couldn&#8217;t click on it. Testing really works!<\/p>\n<h2>Customize Cypress for Drupal<\/h2>\n<p>You can write your own custom Cypress commands, too. Remember the <code>supportFile<\/code> entry in the <code>cypress.config.js<\/code> file? It points to a file that Cypress added, which in turn imports the <code>.\/commands<\/code> files. Incidentally, Cypress is so clever that when importing logic or data fixtures, you don&#8217;t need to specify the file extension, so you import <code>.\/commands<\/code>, not <code>.\/commands.js<\/code>. Cypress looks for any of a dozen or so popular file extensions and understands how to recognize and parse each of them.<\/p>\n<p>Enter commands into <code>commands.js<\/code> to define them:<\/p>\n<pre>\n<code class=\"language-javascript\">\/**\n * Logs out the user.\n *\/\n \nCypress.Commands.add('drupalLogout', () =&gt; {\n  cy.visit('\/user\/logout');\n})\n \n\/**\n * Basic user login command. Requires valid username and password.\n *\n * @param {string} username\n *   The username with which to log in.\n * @param {string} password\n *   The password for the user's account.\n *\/\n \nCypress.Commands.add('loginAs', (username, password) =&gt; {\n  cy.drupalLogout();\n  cy.visit('\/user\/login');\n  cy.get('#edit-name')\n    .type(username);\n  cy.get('#edit-pass').type(password, {\n    log: false,\n  });\n \n  cy.get('#edit-submit').contains('Log in').click();\n});<\/code><\/pre>\n<p>This example defines a custom Cypress command called <code>drupalLogout()<\/code>, which you can use in any subsequent logic, even other custom commands. To log a user out, call <code>cy.drupalLogout()<\/code>. This is the first event in the custom command <code>loginAs<\/code> to ensure that Cypress is logged out before attempting to log in as a specific user.<\/p>\n<p>Using environment variables, you can even create a Cypress command called <code>drush()<\/code>, which you can use to execute Drush commands in your tests or custom commands. Look at how simple this makes it to define a custom Cypress command that logs a user in using their UID:<\/p>\n<pre>\n<code class=\"language-javascript\">\/**\n* Logs a user in by their uid via drush uli.\n*\/\n \nCypress.Commands.add('loginUserByUid', (uid) =&gt; {\n cy.drush('user-login', [], { uid, uri: Cypress.env('baseUrl') })\n   .its('stdout')\n   .then(function (url) {\n     cy.visit(url);\n   });\n});<\/code><\/pre>\n<p>This example uses the <code>drush user-login<\/code> command (<code>drush uli<\/code> for short) and takes the authenticated user to the site&#8217;s base URL.<\/p>\n<p>Consider the security benefit of never reading or storing user passwords in your testing. Personally, I find it amazing that a front-end technology like Cypress can execute Drush commands, which I&#8217;ve always thought of as being very much on the back end.<\/p>\n<h2>Testing, testing<\/h2>\n<p>There&#8217;s a lot more to Cypress, like fixtures (files that hold test data) and various tricks for navigating the sometimes complex data structures that produce a website&#8217;s user interface. For a look into what&#8217;s possible, watch the <a href=\"https:\/\/atendesigngroup.com\/webinar\/cypress-testing-drupal-websites\" target=\"_blank\" rel=\"noopener\">Cypress Testing for Drupal Websites<\/a> webinar, particularly <a href=\"https:\/\/youtu.be\/pKiBuYImoI8?t=1113\" target=\"_blank\" rel=\"noopener\">the section on fixtures that begins at 18:33<\/a>. That webinar goes into greater detail about some interesting use cases, including an Ajax-enabled form. Once you start using it, feel free to use or fork <a href=\"https:\/\/bitbucket.org\/aten_cobadger\/cypress-for-drupal\/src\/main\/\" target=\"_blank\" rel=\"noopener\">Aten&#8217;s public repository of Cypress Testing for Drupal<\/a>.<\/p>\n<p>Happy testing!<\/p>\n<hr>\n<p><em>This article originally appeared on the <a href=\"https:\/\/atendesigngroup.com\/articles\" target=\"_blank\" rel=\"noopener\">Aten blog<\/a> and is republished with permission.<\/em><\/p>\n<\/div>\n<div class=\"clearfix text-formatted field field--name-field-article-subhead field--type-text-long field--label-hidden field__item\">\n<p>Testing makes everything better. Learn how to use Cypress for your Drupal website.<\/p>\n<\/div>\n<div class=\"field field--name-field-lead-image field--type-entity-reference field--label-hidden field__item\">\n<article class=\"media media--type-image media--view-mode-caption\">\n<div class=\"field field--name-field-media-image field--type-image field--label-hidden field__item\">  <img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/www.cryptocabaret.com\/wp-content\/uploads\/2023\/04\/lenovo-thinkpad-laptop-concentration-focus-windows-office.png\" width=\"799\" height=\"447\" alt=\"Business woman on laptop sitting in front of window\" title=\"Woman using laptop concentrating\"><\/div>\n<div class=\"field field--name-field-caption field--type-text-long field--label-hidden caption field__item\"><span class=\"caption__byline\">Image by: <\/span><\/p>\n<p>Image by Mapbox Uncharted ERG,\u00a0<a href=\"https:\/\/creativecommons.org\/licenses\/by\/3.0\/us\/\" rel=\"ugc noopener\" target=\"_blank\">CC-BY 3.0 US<\/a><\/p>\n<\/div>\n<\/article>\n<\/div>\n<div class=\"field field--name-field-tags field--type-entity-reference field--label-hidden field__items\">\n<div class=\"field__item\"><a href=\"https:\/\/opensource.com\/tags\/drupal\" hreflang=\"en\">Drupal<\/a><\/div>\n<div class=\"field__item\"><a href=\"https:\/\/opensource.com\/tags\/web-development\" hreflang=\"en\">Web development<\/a><\/div>\n<\/p><\/div>\n<div class=\"hidden field field--name-field-listicle-title field--type-string field--label-hidden field__item\">What to read next<\/div>\n<div class=\"field field--name-field-default-license field--type-list-string field--label-hidden field__item\"><a rel=\"license\" href=\"http:\/\/creativecommons.org\/licenses\/by-sa\/4.0\/\"><br \/>\n        <img decoding=\"async\" alt=\"Creative Commons License\" src=\"https:\/\/www.cryptocabaret.com\/wp-content\/uploads\/2023\/04\/cc-by-sa--39.png\" title=\"This work is licensed under a Creative Commons Attribution-Share Alike 4.0 International License.\"><\/a>This work is licensed under a Creative Commons Attribution-Share Alike 4.0 International License.<\/div>\n<section class=\"field field--name-field-comments field--type-comment field--label-hidden comment-wrapper\">\n<div class=\"comments__count\">\n<div class=\"login\"><a href=\"https:\/\/opensource.com\/user\/register?absolute=1\">Register<\/a> or <a href=\"https:\/\/opensource.com\/user\/login?current=\/feed&amp;absolute=1\">Login<\/a> to post a comment.<\/div>\n<\/p><\/div>\n<\/section>\n<p class=\"wpematico_credit\"><small>Powered by <a href=\"http:\/\/www.wpematico.com\" target=\"_blank\" rel=\"noopener\">WPeMatico<\/a><\/small><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Test your Drupal website with Cypress cobadger Wed, 04\/26\/2023 &#8211; 03:00 If you don&#8217;t include tests in your Drupal development, chances are it&#8217;s because you think it adds complexity and expense without benefit. Cypress is an open source tool with many benefits: Reliably tests anything that runs in a web browser Works on any web [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":72953,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[307],"tags":[],"class_list":["post-72952","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-open-source"],"_links":{"self":[{"href":"https:\/\/www.cryptocabaret.com\/index.php?rest_route=\/wp\/v2\/posts\/72952","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.cryptocabaret.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.cryptocabaret.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.cryptocabaret.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.cryptocabaret.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=72952"}],"version-history":[{"count":0,"href":"https:\/\/www.cryptocabaret.com\/index.php?rest_route=\/wp\/v2\/posts\/72952\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.cryptocabaret.com\/index.php?rest_route=\/wp\/v2\/media\/72953"}],"wp:attachment":[{"href":"https:\/\/www.cryptocabaret.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=72952"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.cryptocabaret.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=72952"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.cryptocabaret.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=72952"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}