PHPackages                             tappet/tappet - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. tappet/tappet

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

tappet/tappet
=============

v0.2.3(2w ago)06982MITPHPPHP &gt;=8.1CI passing

Since Apr 16Pushed 2w agoCompare

[ Source](https://github.com/nytris/tappet)[ Packagist](https://packagist.org/packages/tappet/tappet)[ RSS](/packages/tappet-tappet/feed)WikiDiscussions main Synced 1w ago

READMEChangelogDependencies (10)Versions (8)Used By (2)

Tappet - Enjoyable GUI testing
==============================

[](#tappet---enjoyable-gui-testing)

[![Build Status](https://github.com/nytris/tappet/workflows/CI/badge.svg)](https://github.com/nytris/tappet/actions?query=workflow%3ACI)

> **\[EXPERIMENTAL\]** - API is unstable and subject to change.

Tappet is a GUI testing framework that lets you write end-to-end tests at a higher level of abstraction than traditional tools encourage. Instead of hunting for CSS selectors or XPath queries, you describe *what* you want to interact with, and Tappet finds it.

The problem with selector-based testing
---------------------------------------

[](#the-problem-with-selector-based-testing)

A typical Cypress test might look like this:

```
cy.get('#save-button').click();
cy.get('.flash-message').should('contain', 'User saved successfully');
```

This approach is fragile: the test is coupled to the IDs, classes, and text content of your HTML. Rename `#save-button` to `#submit-btn`, restructure so that `.flash-message` is applied to a different element, or change the wording of your flash message, and the test breaks, even though the application behaves correctly.

Tappet's approach
-----------------

[](#tappets-approach)

Tappet replaces selector-based targeting with named *handles* wired to DOM elements via `data-ui-*` attributes:

```

Save

    User saved successfully

```

```
// In your Tappet spec:
->act(
    new Enact('save')
)
->assert(
    new ExpectRegionContains('flash', 'User saved successfully')
)
```

Now you can rename the button's ID, change its CSS classes, or even swap it for an `` - none of that affects the test. The `data-ui-interaction="save"` attribute is the stable contract between the application and its tests.

Core abstractions
-----------------

[](#core-abstractions)

Tappet organises its abstractions into four categories, grouped under **Controls** and **Feedback**:

DirectionTypeHTML attributePurposeControl**Field Actions**`data-ui-field`Type into inputs, select options, and interact with form fields by handleFeedback**Field Assertions**`data-ui-field`Assert a field's value, e.g. the content of a text inputControl**Interactions**`data-ui-interaction`Click buttons and follow links without caring about their selector or positionFeedback**Region Assertions**`data-ui-region`Assert the display, e.g. text content of named page areas such as headings or flash messagesFeedback**State Assertions**`data-ui-state`Assert application state by presence of a marker element, decoupled from copySpecs in PHP
------------

[](#specs-in-php)

Test specs are written in PHP using a fluent BDD-style arrange/act/assert API:

```
