GithubHelp home page GithubHelp logo

cypress's Introduction

Cypress for Drupal

Overview

This module integrates the Drupal content management system with Cypress E2E testing. It will help you to:

  • Use Cypress for testing whole Drupal projects, including configuration.
  • Include Cypress tests in custom Drupal modules.
  • Ship custom Cypress commands and predefined cucumber step definitions with Drupal modules.

It also includes some handy Cypress plugins out of the box:

Requirements and Installation

Apart from standard system requirements, you will need Composer and npm available on your system first. From there, this is shortest path to get it up and running:

  1. Download and extract Drupal

    curl -O https://ftp.drupal.org/files/projects/drupal-8.8.5.tar.gz
    tar -xvzf drupal-8.8.5.tar.gz
    cd drupal-8.8.5
  2. Install the Cypress Module and upgrade PHPUnit

    composer require drupal/cypress
    composer require phpunit/phpunit:^7 symfony/phpunit-bridge phpspec/prophecy sebastian/global-state:^2 sebastian/environment:^3.1 phpunit/php-code-coverage:^6
  3. Install the minimal profile and the Cypress module

    php core/scripts/drupal install minimal
    drush en cypress -y
  4. In case of doubt, loosen the directory permissions so the module can copy settings files for you. If you don't, it might ask you to do that yourself.

    chmod 755 sites/default
  5. Start a test server and run tests

    vendor/bin/drush serve &
    vendor/bin/drush cypress:run

The test suite for the Cypress module itself, located in the tests\Cypress, should have been executed. They also serve as examples on how to write Cypress tests yourself.

How meta!

You are good to go, now draw the rest of the drowsy the owl!

A detailed instruction on how to draw an owl

Configuration

Back to serious. What happened now? A new directory called drupal-cypress-environment was created, which you can safely add to .gitignore. All dependencies have been downloaded there and the Drupal installation was scanned for modules with a tests/Cypress directory which where added as new test suites. Additionally a testing.services.yml file should have been created in your sites/default directory. This one can be added to your git repository, since it allows you to adapt configuration:

  • cypress.enabled: This one is important! It is disabled by default and should be enabled only in testing.services.yml. It opens up backdoors for Cypress to speed up tests, which are huge security threats for a publicly accessible website.
  • cypress.executable.drush: A path to the drush executable that will be used by cypress. Relative to the Drupal root directory. It defaults to vendor/bin/drush, which is where it will be if you simply download Drupal as shown above. But if you use a different directory layout (like the [composer template]), you might have to adapt this.
  • cypress.test_suites: The module will register a test suite for each module containing a tests/Cypress directory with the modules machine name. This parameter allows to add other directories as well.

The cypress:run command will just run all scoped tests, while cypress:open starts the Cypress user interface for interactive debugging.

composer template

Test suites

A test suite can hook into the test framework in different ways by simply containing certain files or directories.

  1. package.json: If a test suite contains a package.json file, its dependencies and additional settings will be merged into the global package that is automatically maintained in drupal-cypress-environment.
  2. integration: The actual tests and implementations. The modules uses the Cucumber preprocessor for Cypress in nonGlobalStepDefinitions mode. This means that test specifications are written in *.feature files and implementations in arbitrary *.js files stored in a directory with the same name as the *.feature file. Please refer to the Cucumber preprocessor documentation for a lot more details on test organisation.
  3. steps: This directory will be scanned for *.js files that contain global step definitions. These are available to all scenarios. Not just within the current suites integration folder, but also to other test suites. This can be used to share common steps defined by a Drupal module.
  4. plugins/index.js: This file will be automatically added to Cypress plugin system and allows to add additional extensions that are not covered out of the box by this module.
  5. support/index.js: That's the entry point for anything that would go into Cypress notion of support files. Here, for example, test suites can share reusable commands.

Drush commands

The module comes with list of simple drush commands.

drush cypress:list

Simply lists all discovered test suites. Nothing fancy.

drush cypress:run

Will run all or a specific set of test suites. Also accepts an option to define [tags] that should be run. [tags]: https://github.com/TheBrainFamily/cypress-cucumber-preprocessor#running-tagged-tests

Examples:

# Run all test suites
drush cypress:run

# Run all tests of a specific suite
drush cypress:run mytestsuite

# Run all tests within a folder in a specific suite
drush cypress:run mytestsuite:sub/folder

# Run a specific spec file
drush cypress:run mytestsuite:sub/folder/Fancy.feature

# Run all tests matching a certain tags expression
drush cypress:run --tags "@Completed and @Issue-123"

# Both options can be combined
drush cypress:run mytestsuite:sub/folder --tags "@Completed and @Issue-123"

drush cypress:open

Starts the Cypress user interface for running tests interactively.

drush cypress:init

Rebuilds the Cypress environment. This is automatically invoked when running drush cypress:run or drush cypress:open, but can be used if you need to run cypress directly from within drupal-cypress-environment.

Predefined commands

The Cypress module comes with a set of predefined commands that can be used by other test suites to easily interact with Drupal.

cy.drupalInstall()

Install Drupal at the beginning of your test case. This command reuses the test setup behind Drupals Browsertests. If the tests are run against a SQLite database, it also automatically caches the install process and reuses it across test runs to speed things. It takes a set of options as arguments:

The profile option defines the installation profile to use. It defaults to testing.

cy.drupalInstall({profile: 'umami_demo'});

The value of config can be the path to a configuration sync directory, relative to the Drupal root. This can be used to run tests against a fully configured project. The chosen profile has to match the one in configuration in this case.

cy.drupalInstall({config: '../config/sync'});

setup allows to define a custom setup script (identical to nightwatch test setups). The path should be prefixed with the test suites name.

cy.drupalInstall({setup: 'cypress:integration/CypressTestSiteInstallScript.php'});

The cache property allows to define a persistent cache file that can be placed anywhere relative to the Drupal root directory. It can be used to maintain a cached version of the installation to speed up exection on build servers as well as testing update procedures properly. After a site has been recreated from cache, the setup process will automatically run drush updb -y and drush cim -y.

cy.drupalInstall({cache: '../install-cache.zip'});

Using the strictConfigCheck flag, Drupal config checking can be disabled. This only makes sense in combination with a config directory.

cy.drupalInstall({strictConfigCheck: false});

cy.drupalUninstall

This should be called at the end of each test case (preferrably in afterEach), to clean up test site installs created by cy.drupalInstall.

cy.drupalUninstall();

cy.drush

Execute arbitrary drush commands against the current test site.

cy.drush('cron');

cy.drupalScript

Execute a simple PHP script in the test suite. Can be used for test content setup or other tasks that don't have to be run through the user interface. The script is executed in context of a fully booted Drupal environment and has access to the container much like drush scr.

The first argument is the script path, relative to your test suite. The second an arbitrary context object that will be passed to the script as an $args variable.

cy.drupalScript('cypress:integration/Scripts/testPage.php', {title: "Test page"});

cy.drupalSession

Control the user session a test case operates in. The settings will persist across subsequent requests within this test case.

user to automatically log in a specific account:

cy.drupalSession({user: 'admin'});

language to select the language the system is accessed in:

cy.drupalSession({language: 'de'});

workspace to make the system automatically switch to a specific workspace:

cy.drupalSession({workspace: 'stage'});

... and a boolean flag to show or hide the toolbar during the test run. By default the toolbar is turned of to avoid problems with Cypress not being able to click elements because they are hidden behind it.

cy.drupalSession({toolbar: true});

cy.drupalVisitEntity

Search for a Drupal entity by properties and visit one of the registered link patterns. This allows to easily access entity pages without relying on internal entity id's. This example would bring you to the edit page of a node with title Testpage.

cy.drupalVisitEntity('node', {title: "Testpage"}, 'edit-form');

cypress's People

Contributors

frega avatar jamiehollern avatar leksat avatar pmelab avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cypress's Issues

cy.clearCookies() also clears SIMPLETEST_USER_AGENT

Might lead to hard to debug problems since the next request will execute against sites/default instead of the test site. cy.clearCookies should be replaced to clear cookies except SIMPLETEST_USER_AGENT.

Best way to set Cypress base_url globally?

It seems like the cypress runner uses http://localhost:8888 as the default base_url. What is the best way to set this variable globally so all tests for a site use a custom one? In non-Drupal projects I'd just put this in the cypress.json file, but the only cypress.json file I see is in the drupal-cypress-environment directory, which is git ignored and seems to get rebuilt with every test run.

I've been able to set a custom base url by running export CYPRESS_BASE_URL=http://local.mysiteimtesting.com && drush cypress:run but I'd prefer not to have to pass in env variables this way.

I appreciate any help with this, and thanks for making this integration module for Drupal.

Speedup installation of NPM dependencies

Currently NpmProjectManager::ensurePackageVersion() runs npm install for each dependency.

An alternative could be:

  • Start with a predefined package.json having merge-package.json in dependencies.
  • Use merge-package.json to merge all package.json files at once.

As a result, we will need to execute npm install only two times.

module has a hard dependency to workspace module without declaring it

this will lead to a PHP error when trying to enable the module.

PHP Fatal error:  Interface 'Drupal\workspaces\Negotiator\WorkspaceNegotiatorInterface' not found in /var/www/web/modules/contrib/cypress/src/Negotiator/CypressWorkspaceNegotiator.php on line 18
PHP Stack trace:
PHP   1. {main}() /var/www/vendor/drush/drush/drush:0
PHP   2. require() /var/www/vendor/drush/drush/drush:4
PHP   3. Drush\Runtime\Runtime->run() /var/www/vendor/drush/drush/drush.php:72
PHP   4. Drush\Runtime\Runtime->doRun() /var/www/vendor/drush/drush/src/Runtime/Runtime.php:49
PHP   5. Drush\Application->run() /var/www/vendor/drush/drush/src/Runtime/Runtime.php:118
PHP   6. Drush\Application->doRun() /var/www/vendor/symfony/console/Application.php:148
PHP   7. Drush\Application->doRunCommand() /var/www/vendor/symfony/console/Application.php:255
PHP   8. Consolidation\AnnotatedCommand\AnnotatedCommand->run() /var/www/vendor/symfony/console/Application.php:1000
PHP   9. Consolidation\AnnotatedCommand\AnnotatedCommand->execute() /var/www/vendor/symfony/console/Command/Command.php:255
PHP  10. Consolidation\AnnotatedCommand\CommandProcessor->process() /var/www/vendor/consolidation/annotated-command/src/AnnotatedCommand.php:302
PHP  11. Consolidation\AnnotatedCommand\CommandProcessor->validateRunAndAlter() /var/www/vendor/consolidation/annotated-command/src/CommandProcessor.php:176
PHP  12. Consolidation\AnnotatedCommand\CommandProcessor->runCommandCallback() /var/www/vendor/consolidation/annotated-command/src/CommandProcessor.php:212
PHP  13. call_user_func_array:{/var/www/vendor/consolidation/annotated-command/src/CommandProcessor.php:257}() /var/www/vendor/consolidation/annotated-command/src/CommandProcessor.php:257
PHP  14. Drush\Drupal\Commands\pm\PmCommands->enable() /var/www/vendor/consolidation/annotated-command/src/CommandProcessor.php:257
PHP  15. Drupal\Core\ProxyClass\Extension\ModuleInstaller->install() /var/www/vendor/drush/drush/src/Drupal/Commands/pm/PmCommands.php:78
PHP  16. Drupal\Core\Extension\ModuleInstaller->install() /var/www/web/core/lib/Drupal/Core/ProxyClass/Extension/ModuleInstaller.php:83
PHP  17. Drupal\Core\Extension\ModuleInstaller->updateKernel() /var/www/web/core/lib/Drupal/Core/Extension/ModuleInstaller.php:211
PHP  18. Drush\Drupal\DrupalKernel->updateModules() /var/www/web/core/lib/Drupal/Core/Extension/ModuleInstaller.php:573
PHP  19. Drush\Drupal\DrupalKernel->initializeContainer() /var/www/web/core/lib/Drupal/Core/DrupalKernel.php:826
PHP  20. Drush\Drupal\DrupalKernel->initializeContainer() /var/www/vendor/drush/drush/src/Drupal/DrupalKernelTrait.php:69
PHP  21. Drush\Drupal\DrupalKernel->compileContainer() /var/www/web/core/lib/Drupal/Core/DrupalKernel.php:902
PHP  22. Drupal\Core\DependencyInjection\ContainerBuilder->compile() /var/www/web/core/lib/Drupal/Core/DrupalKernel.php:1321
PHP  23. Symfony\Component\DependencyInjection\Compiler\Compiler->compile() /var/www/vendor/symfony/dependency-injection/ContainerBuilder.php:789
PHP  24. Drupal\webprofiler\Compiler\ServicePass->process() /var/www/vendor/symfony/dependency-injection/Compiler/Compiler.php:140
PHP  25. Drupal\webprofiler\Compiler\ServicePass->extractData() /var/www/web/modules/contrib/devel/webprofiler/src/Compiler/ServicePass.php:26
PHP  26. ReflectionClass->__construct() /var/www/web/modules/contrib/devel/webprofiler/src/Compiler/ServicePass.php:73
PHP  27. spl_autoload_call() /var/www/web/modules/contrib/devel/webprofiler/src/Compiler/ServicePass.php:73
PHP  28. Composer\Autoload\ClassLoader->loadClass() /var/www/web/modules/contrib/devel/webprofiler/src/Compiler/ServicePass.php:73
PHP  29. Composer\Autoload\includeFile() /var/www/vendor/composer/ClassLoader.php:322
PHP  30. include() /var/www/vendor/composer/ClassLoader.php:444

Is there a way around this? I do not want to enable workspaces just to run my tests.

"Unable to create "symbolic" link due to error code 1314"

When I run drush cypress:run, i get the following error:

In Filesystem.php line 391:  
  Unable to create "symbolic" link due to error code 1314: 'A required privilege is not held by the client'. Do you have the required Administrator-rights?

My account has admin privileges but my terminal session, does not. If I run from a elevated terminal, it appears to work.

I think Windows require an elevated terminal to use symbolic links. It there another way I can use this package without requiring an elevated terminal?

OS: Win10
PHP: 7.3
Drupal: 8.9.1

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.