Merge pull request #4341 from hashicorp/feature/more-acceptance-tests

UI - More acceptance tests
This commit is contained in:
John Cowen 2018-07-06 11:03:25 +01:00 committed by GitHub
commit 865a20c03e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
52 changed files with 536 additions and 254 deletions

View File

@ -13,37 +13,27 @@ You will need the following things properly installed on your computer.
## Installation ## Installation
* `git clone <repository-url>` this repository * `git clone https://github.com/hashicorp/consul.git` this repository
* `cd ui` * `cd ui-v2`
* `yarn install` * `yarn install`
## Running / Development ## Running / Development
* `yarn run start` * `make start-api` or `yarn start:api` (this starts a Consul API double running
on http://localhost:3000)
* `make start` or `yarn start` to start the ember app that connects to the
above API double
* Visit your app at [http://localhost:4200](http://localhost:4200). * Visit your app at [http://localhost:4200](http://localhost:4200).
* Visit your tests at [http://localhost:4200/tests](http://localhost:4200/tests). * Visit your tests at [http://localhost:4200/tests](http://localhost:4200/tests).
### Code Generators ### Code Generators
Make use of the many generators for code, try `ember help generate` for more details Make use of the many generators for code, try `ember help generate` for more details
### Running Tests ### Running Tests
* `ember test` You do not need to run `make start-api`/`yarn run start:api` to run the tests
* `ember test --server`
### Building * `make test` or `yarn run test`
* `make test-view` or `yarn run test:view` to view the tests running in Chrome
* `ember build` (development)
* `ember build --environment production` (production)
### Deploying
## Further Reading / Useful Links
* [ember.js](https://emberjs.com/)
* [ember-cli](https://ember-cli.com/)
* Development Browser Extensions
* [ember inspector for chrome](https://chrome.google.com/webstore/detail/ember-inspector/bmdblncegkenkacieihfhpjfppoconhi)
* [ember inspector for firefox](https://addons.mozilla.org/en-US/firefox/addon/ember-inspector/)

View File

@ -35,7 +35,7 @@
{{# if (and (not create) (not-eq item.ID 'anonymous')) }} {{# if (and (not create) (not-eq item.ID 'anonymous')) }}
{{#confirmation-dialog message='Are you sure you want to delete this ACL token?'}} {{#confirmation-dialog message='Are you sure you want to delete this ACL token?'}}
{{#block-slot 'action' as |confirm|}} {{#block-slot 'action' as |confirm|}}
<button type="button" class="type-delete" {{action confirm 'delete' item parent}}>Delete</button> <button type="button" data-test-delete class="type-delete" {{action confirm 'delete' item parent}}>Delete</button>
{{/block-slot}} {{/block-slot}}
{{#block-slot 'dialog' as |execute cancel message|}} {{#block-slot 'dialog' as |execute cancel message|}}
<p> <p>

View File

@ -1,7 +1,7 @@
{{#app-view class="acl edit" loading=isLoading}} {{#app-view class="acl edit" loading=isLoading}}
{{#block-slot 'breadcrumbs'}} {{#block-slot 'breadcrumbs'}}
<ol> <ol>
<li><a href={{href-to 'dc.acls'}}>All Tokens</a></li> <li><a data-test-back href={{href-to 'dc.acls'}}>All Tokens</a></li>
</ol> </ol>
{{/block-slot}} {{/block-slot}}
{{#block-slot 'header'}} {{#block-slot 'header'}}
@ -35,7 +35,7 @@
<button type="button" {{ action "clone" item }}>Clone token</button> <button type="button" {{ action "clone" item }}>Clone token</button>
{{#confirmation-dialog message='Are you sure you want to use this ACL token?'}} {{#confirmation-dialog message='Are you sure you want to use this ACL token?'}}
{{#block-slot 'action' as |confirm|}} {{#block-slot 'action' as |confirm|}}
<button type="button" {{ action confirm 'use' item }}>Use token</button> <button data-test-use type="button" {{ action confirm 'use' item }}>Use token</button>
{{/block-slot}} {{/block-slot}}
{{#block-slot 'dialog' as |execute cancel message|}} {{#block-slot 'dialog' as |execute cancel message|}}
<p> <p>

View File

@ -5,7 +5,7 @@
</h1> </h1>
{{/block-slot}} {{/block-slot}}
{{#block-slot 'actions'}} {{#block-slot 'actions'}}
<a href="{{href-to 'dc.acls.create'}}" class="type-create">Create</a> <a data-test-create href="{{href-to 'dc.acls.create'}}" class="type-create">Create</a>
{{/block-slot}} {{/block-slot}}
{{#block-slot 'toolbar'}} {{#block-slot 'toolbar'}}
{{#if (gt items.length 0) }} {{#if (gt items.length 0) }}

View File

@ -64,7 +64,7 @@
{{# if (and item.ID (not-eq item.ID 'anonymous')) }} {{# if (and item.ID (not-eq item.ID 'anonymous')) }}
{{#confirmation-dialog message='Are you sure you want to delete this Intention?'}} {{#confirmation-dialog message='Are you sure you want to delete this Intention?'}}
{{#block-slot 'action' as |confirm|}} {{#block-slot 'action' as |confirm|}}
<button type="button" class="type-delete" {{action confirm 'delete' item parent}}>Delete</button> <button data-test-delete type="button" class="type-delete" {{action confirm 'delete' item parent}}>Delete</button>
{{/block-slot}} {{/block-slot}}
{{#block-slot 'dialog' as |execute cancel message|}} {{#block-slot 'dialog' as |execute cancel message|}}
<p> <p>

View File

@ -1,7 +1,7 @@
{{#app-view class="acl edit" loading=isLoading}} {{#app-view class="acl edit" loading=isLoading}}
{{#block-slot 'breadcrumbs'}} {{#block-slot 'breadcrumbs'}}
<ol> <ol>
<li><a href={{href-to 'dc.intentions'}}>All Intentions</a></li> <li><a data-test-back href={{href-to 'dc.intentions'}}>All Intentions</a></li>
</ol> </ol>
{{/block-slot}} {{/block-slot}}
{{#block-slot 'header'}} {{#block-slot 'header'}}

View File

@ -5,7 +5,7 @@
</h1> </h1>
{{/block-slot}} {{/block-slot}}
{{#block-slot 'actions'}} {{#block-slot 'actions'}}
<a href="{{href-to 'dc.intentions.create'}}" class="type-create">Create</a> <a data-test-create href="{{href-to 'dc.intentions.create'}}" class="type-create">Create</a>
{{/block-slot}} {{/block-slot}}
{{#block-slot 'toolbar'}} {{#block-slot 'toolbar'}}
{{#if (gt items.length 0) }} {{#if (gt items.length 0) }}
@ -27,7 +27,7 @@
{{/block-slot}} {{/block-slot}}
{{#block-slot 'row'}} {{#block-slot 'row'}}
<td class="source" data-test-intention="{{item.ID}}"> <td class="source" data-test-intention="{{item.ID}}">
<a href={{href-to 'dc.intentions.edit' item.ID}}> <a href={{href-to 'dc.intentions.edit' item.ID}} data-test-intention-source="{{item.SourceName}}">
{{#if (eq item.SourceName '*') }} {{#if (eq item.SourceName '*') }}
All Services (*) All Services (*)
{{else}} {{else}}
@ -35,10 +35,10 @@
{{/if}} {{/if}}
</a> </a>
</td> </td>
<td class="intent-{{item.Action}}"> <td class="intent-{{item.Action}}" data-test-intention-action="{{item.Action}}">
<strong>{{item.Action}}</strong> <strong>{{item.Action}}</strong>
</td> </td>
<td class="destination"> <td class="destination" data-test-intention-destination="{{item.DestinationName}}">
{{#if (eq item.DestinationName '*') }} {{#if (eq item.DestinationName '*') }}
All Services (*) All Services (*)
{{else}} {{else}}
@ -58,7 +58,7 @@
<a href={{href-to 'dc.intentions.edit' item.ID}}>Edit</a> <a href={{href-to 'dc.intentions.edit' item.ID}}>Edit</a>
</li> </li>
<li> <li>
<a onclick={{action confirm 'delete' item}}>Delete</a> <a data-test-delete onclick={{action confirm 'delete' item}}>Delete</a>
</li> </li>
</ul> </ul>
{{/action-group}} {{/action-group}}

View File

@ -33,7 +33,7 @@
<button type="reset" {{ action "cancel" item parent}}>Cancel changes</button> <button type="reset" {{ action "cancel" item parent}}>Cancel changes</button>
{{#confirmation-dialog message='Are you sure you want to delete this key?'}} {{#confirmation-dialog message='Are you sure you want to delete this key?'}}
{{#block-slot 'action' as |confirm|}} {{#block-slot 'action' as |confirm|}}
<button type="button" class="type-delete" {{action confirm 'delete' item parent}}>Delete</button> <button data-test-delete type="button" class="type-delete" {{action confirm 'delete' item parent}}>Delete</button>
{{/block-slot}} {{/block-slot}}
{{#block-slot 'dialog' as |execute cancel message|}} {{#block-slot 'dialog' as |execute cancel message|}}
<p> <p>

View File

@ -1,7 +1,7 @@
{{#app-view class="kv edit" loading=isLoading}} {{#app-view class="kv edit" loading=isLoading}}
{{#block-slot 'breadcrumbs'}} {{#block-slot 'breadcrumbs'}}
<ol> <ol>
<li><a href={{href-to 'dc.kv.index'}}>Key / Values</a></li> <li><a data-test-back href={{href-to 'dc.kv.index'}}>Key / Values</a></li>
{{#if (not-eq parent.Key '/') }} {{#if (not-eq parent.Key '/') }}
{{#each (slice 0 -1 (split parent.Key '/')) as |breadcrumb index|}} {{#each (slice 0 -1 (split parent.Key '/')) as |breadcrumb index|}}
<li><a href={{href-to 'dc.kv.folder' (join '/' (append (slice 0 (add index 1) (split parent.Key '/')) ''))}}>{{breadcrumb}}</a></li> <li><a href={{href-to 'dc.kv.folder' (join '/' (append (slice 0 (add index 1) (split parent.Key '/')) ''))}}>{{breadcrumb}}</a></li>

View File

@ -27,9 +27,9 @@
{{/block-slot}} {{/block-slot}}
{{#block-slot 'actions'}} {{#block-slot 'actions'}}
{{#if (not-eq parent.Key '/') }} {{#if (not-eq parent.Key '/') }}
<a href="{{href-to 'dc.kv.create' parent.Key}}" class="type-create">Create</a> <a data-test-create href="{{href-to 'dc.kv.create' parent.Key}}" class="type-create">Create</a>
{{else}} {{else}}
<a href="{{href-to 'dc.kv.root-create'}}" class="type-create">Create</a> <a data-test-create href="{{href-to 'dc.kv.root-create'}}" class="type-create">Create</a>
{{/if}} {{/if}}
{{/block-slot}} {{/block-slot}}
{{#block-slot 'content'}} {{#block-slot 'content'}}

View File

@ -37,7 +37,7 @@
<td> <td>
{{#confirmation-dialog message='Are you sure you want to invalidate this session?'}} {{#confirmation-dialog message='Are you sure you want to invalidate this session?'}}
{{#block-slot 'action' as |confirm|}} {{#block-slot 'action' as |confirm|}}
<button type="button" class="type-delete" {{action confirm 'invalidateSession' item}}>Invalidate</button> <button data-test-delete type="button" class="type-delete" {{action confirm 'invalidateSession' item}}>Invalidate</button>
{{/block-slot}} {{/block-slot}}
{{#block-slot 'dialog' as |execute cancel message|}} {{#block-slot 'dialog' as |execute cancel message|}}
<p> <p>

View File

@ -1,7 +1,7 @@
{{#app-view class="node show"}} {{#app-view class="node show"}}
{{#block-slot 'breadcrumbs'}} {{#block-slot 'breadcrumbs'}}
<ol> <ol>
<li><a href={{href-to 'dc.nodes'}}>All Nodes</a></li> <li><a data-test-back href={{href-to 'dc.nodes'}}>All Nodes</a></li>
</ol> </ol>
{{/block-slot}} {{/block-slot}}
{{#block-slot 'header'}} {{#block-slot 'header'}}

View File

@ -1,7 +1,7 @@
{{#app-view class="service show"}} {{#app-view class="service show"}}
{{#block-slot 'breadcrumbs'}} {{#block-slot 'breadcrumbs'}}
<ol> <ol>
<li><a href={{href-to 'dc.services'}}>All Services</a></li> <li><a data-test-back href={{href-to 'dc.services'}}>All Services</a></li>
</ol> </ol>
{{/block-slot}} {{/block-slot}}
{{#block-slot 'header'}} {{#block-slot 'header'}}

View File

@ -2,7 +2,7 @@
"name": "consul-ui", "name": "consul-ui",
"version": "2.2.0", "version": "2.2.0",
"private": true, "private": true,
"description": "The web ui for Consul, by HashiCorp.", "description": "The web UI for Consul, by HashiCorp.",
"directories": { "directories": {
"doc": "doc", "doc": "doc",
"test": "tests" "test": "tests"

View File

@ -1,5 +1,5 @@
@setupApplicationTest @setupApplicationTest
Feature: dc / components /acl filter: Acl Filter Feature: components / acl filter: Acl Filter
In order to find the acl token I'm looking for easier In order to find the acl token I'm looking for easier
As a user As a user
I should be able to filter by type and freetext search tokens by name and token I should be able to filter by type and freetext search tokens by name and token

View File

@ -0,0 +1,55 @@
@setupApplicationTest
Feature: components / intention filter: Intention Filter
In order to find the intention I'm looking for easier
As a user
I should be able to filter by 'policy' (allow/deny) and freetext search tokens by source and destination
Scenario: Filtering [Model]
Given 1 datacenter model with the value "dc-1"
And 2 [Model] models
When I visit the [Page] page for yaml
---
dc: dc-1
---
Then the url should be [Url]
Then I see 2 [Model] models
And I see allIsSelected on the filter
When I click allow on the filter
Then I see allowIsSelected on the filter
And I see 1 [Model] model
And I see 1 [Model] model with the action "allow"
When I click deny on the filter
Then I see denyIsSelected on the filter
And I see 1 [Model] model
And I see 1 [Model] model with the action "deny"
When I click all on the filter
Then I see 2 [Model] models
Then I see allIsSelected on the filter
Then I fill in with yaml
---
s: alarm
---
And I see 1 [Model] model
And I see 1 [Model] model with the source "alarm"
Then I fill in with yaml
---
s: feed
---
And I see 1 [Model] model
And I see 1 [Model] model with the destination "feed"
Then I fill in with yaml
---
s: transmitter
---
And I see 2 [Model] models
And I see 1 [Model] model with the source "transmitter"
And I see 1 [Model] model with the destination "transmitter"
Where:
---------------------------------------------
| Model | Page | Url |
| intention | intentions | /dc-1/intentions |
---------------------------------------------

View File

@ -1,5 +1,5 @@
@setupApplicationTest @setupApplicationTest
Feature: Text input Feature: components / text-input: Text input
Background: Background:
Given 1 datacenter model with the value "dc-1" Given 1 datacenter model with the value "dc-1"
Scenario: Scenario:

View File

@ -1,17 +0,0 @@
@setupApplicationTest
Feature: dc / acls / delete: ACL Delete
Scenario: Delete ACL
Given 1 datacenter model with the value "datacenter"
And 1 acl model from yaml
---
Name: something
ID: key
---
When I visit the acls page for yaml
---
dc: datacenter
---
And I click actions on the acls
And I click delete on the acls
And I click confirmDelete on the acls
Then a PUT request is made to "/v1/acl/destroy/key?dc=datacenter"

View File

@ -0,0 +1,40 @@
@setupApplicationTest
Feature: dc / acls / use: Using an ACL token
Background:
Given 1 datacenter model with the value "datacenter"
And 1 acl model from yaml
---
ID: token
---
Scenario: Using an ACL token from the listing page
When I visit the acls page for yaml
---
dc: datacenter
---
Then I have settings like yaml
---
token: ~
---
And I click actions on the acls
And I click use on the acls
And I click confirmUse on the acls
Then I have settings like yaml
---
token: token
---
Scenario: Using an ACL token from the detail page
When I visit the acl page for yaml
---
dc: datacenter
acl: token
---
Then I have settings like yaml
---
token: ~
---
And I click use
And I click confirmUse
Then I have settings like yaml
---
token: token
---

View File

@ -1,16 +0,0 @@
@setupApplicationTest
Feature: dc / kvs / delete: KV Delete
Scenario: Delete ACL
Given 1 datacenter model with the value "datacenter"
And 1 kv model from yaml
---
- key-name
---
When I visit the kvs page for yaml
---
dc: datacenter
---
And I click actions on the kvs
And I click delete on the kvs
And I click confirmDelete on the kvs
Then a DELETE request is made to "/v1/kv/key-name?dc=datacenter"

View File

@ -0,0 +1,26 @@
@setupApplicationTest
Feature: dc / nodes / sessions / invalidate: Invalidate Lock Sessions
In order to invalidate a lock session
As a user
I should be able to invalidate a lock session by clicking a button and confirming
Scenario: Given 2 lock sessions
Given 1 datacenter model with the value "dc1"
And 1 node model from yaml
---
- ID: node-0
---
And 2 session models from yaml
---
- ID: 7bbbd8bb-fff3-4292-b6e3-cfedd788546a
- ID: 7ccd0bd7-a5e0-41ae-a33e-ed3793d803b2
---
When I visit the node page for yaml
---
dc: dc1
node: node-0
---
And I click lockSessions on the tabs
Then I see lockSessionsIsSelected on the tabs
And I click delete on the sessions
And I click confirmDelete on the sessions
Then a PUT request is made to "/v1/session/destroy/7bbbd8bb-fff3-4292-b6e3-cfedd788546a?dc=dc1"

View File

@ -0,0 +1,34 @@
@setupApplicationTest
Feature: deleting: Deleting from the listing and the detail page with confirmation
Scenario: Deleting a [Model] from the [Model] listing page
Given 1 datacenter model with the value "datacenter"
And 1 [Model] model from json
---
[Data]
---
When I visit the [Model]s page for yaml
---
dc: datacenter
---
And I click actions on the [Model]s
And I click delete on the [Model]s
And I click confirmDelete on the [Model]s
Then a [Method] request is made to "[URL]"
When I visit the [Model] page for yaml
---
dc: datacenter
[Slug]
---
And I click delete
And I click confirmDelete
Then a [Method] request is made to "[URL]"
Where:
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| Model | Method | URL | Data | Slug |
| acl | PUT | /v1/acl/destroy/something?dc=datacenter | {"Name": "something", "ID": "something"} | acl: something |
| kv | DELETE | /v1/kv/key-name?dc=datacenter | ["key-name"] | kv: key-name |
| intention | DELETE | /v1/connect/intentions/ee52203d-989f-4f7a-ab5a-2bef004164ca?dc=datacenter | {"SourceName": "name", "ID": "ee52203d-989f-4f7a-ab5a-2bef004164ca"} | intention: ee52203d-989f-4f7a-ab5a-2bef004164ca |
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@ignore
Scenario: Sort out the wide tables ^
Then ok

View File

@ -8,36 +8,74 @@ Feature: Page Navigation
dc: dc-1 dc: dc-1
--- ---
Then the url should be /dc-1/services Then the url should be /dc-1/services
Scenario: Clicking [Link] in the navigation takes me to [Url] Scenario: Clicking [Link] in the navigation takes me to [URL]
When I visit the services page for yaml When I visit the services page for yaml
--- ---
dc: dc-1 dc: dc-1
--- ---
When I click [Link] on the navigation When I click [Link] on the navigation
Then the url should be [Url] Then the url should be [URL]
Where: Where:
-------------------------------------- ----------------------------------------
| Link | Url | | Link | URL |
| nodes | /dc-1/nodes | | nodes | /dc-1/nodes |
| kvs | /dc-1/kv | | kvs | /dc-1/kv |
| acls | /dc-1/acls | | acls | /dc-1/acls |
| intentions | /dc-1/intentions |
| settings | /settings | | settings | /settings |
-------------------------------------- ----------------------------------------
Scenario: Clicking a [Item] in the [Model] listing Scenario: Clicking a [Item] in the [Model] listing and back again
When I visit the [Model] page for yaml When I visit the [Model] page for yaml
--- ---
dc: dc-1 dc: dc-1
--- ---
When I click [Item] on the [Model] When I click [Item] on the [Model]
Then the url should be [Url] Then the url should be [URL]
And I click "[data-test-back]"
Then the url should be [Back]
Where: Where:
-------------------------------------------------------- --------------------------------------------------------------------------------------------------------
| Item | Model | Url | | Item | Model | URL | Back |
| service | services | /dc-1/services/service-0 | | service | services | /dc-1/services/service-0 | /dc-1/services |
| node | nodes | /dc-1/nodes/node-0 | | node | nodes | /dc-1/nodes/node-0 | /dc-1/nodes |
| kv | kvs | /dc-1/kv/necessitatibus-0/edit | | kv | kvs | /dc-1/kv/necessitatibus-0/edit | /dc-1/kv |
| acl | acls | /dc-1/acls/anonymous | | acl | acls | /dc-1/acls/anonymous | /dc-1/acls |
-------------------------------------------------------- | intention | intentions | /dc-1/intentions/ee52203d-989f-4f7a-ab5a-2bef004164ca | /dc-1/intentions |
--------------------------------------------------------------------------------------------------------
Scenario: Clicking a [Item] in the [Model] listing and canceling
When I visit the [Model] page for yaml
---
dc: dc-1
---
When I click [Item] on the [Model]
Then the url should be [URL]
And I click "[type=reset]"
Then the url should be [Back]
Where:
--------------------------------------------------------------------------------------------------------
| Item | Model | URL | Back |
| kv | kvs | /dc-1/kv/necessitatibus-0/edit | /dc-1/kv |
| acl | acls | /dc-1/acls/anonymous | /dc-1/acls |
| intention | intentions | /dc-1/intentions/ee52203d-989f-4f7a-ab5a-2bef004164ca | /dc-1/intentions |
--------------------------------------------------------------------------------------------------------
@ignore @ignore
Scenario: Clicking a kv in the kvs listing, without depending on the salt ^ Scenario: Clicking items in the listings, without depending on the salt ^
Then ok
Scenario: Clicking create in the [Model] listing
When I visit the [Model] page for yaml
---
dc: dc-1
---
When I click create
Then the url should be [URL]
And I click "[data-test-back]"
Then the url should be [Back]
Where:
------------------------------------------------------------------------
| Item | Model | URL | Back |
| kv | kvs | /dc-1/kv/create | /dc-1/kv |
| acl | acls | /dc-1/acls/create | /dc-1/acls |
| intention | intentions | /dc-1/intentions/create | /dc-1/intentions |
------------------------------------------------------------------------
Scenario: Using I click on should change the currentPage ^
Then ok Then ok

View File

@ -7,6 +7,10 @@ Feature: settings / update: Update Settings
Given 1 datacenter model with the value "datacenter" Given 1 datacenter model with the value "datacenter"
When I visit the settings page When I visit the settings page
Then the url should be /settings Then the url should be /settings
Then I have settings like yaml
---
token: ~
---
And I submit And I submit
Then I have settings like yaml Then I have settings like yaml
--- ---

View File

@ -1,4 +1,4 @@
import steps from '../../steps'; import steps from '../steps';
// step definitions that are shared between features should be moved to the // step definitions that are shared between features should be moved to the
// tests/acceptance/steps/steps.js file // tests/acceptance/steps/steps.js file

View File

@ -0,0 +1,10 @@
import steps from '../../../steps';
// step definitions that are shared between features should be moved to the
// tests/acceptance/steps/steps.js file
export default function(assert) {
return steps(assert).then('I should find a file', function() {
assert.ok(true, this.step);
});
}

View File

@ -0,0 +1,11 @@
import steps from './steps';
// step definitions that are shared between features should be moved to the
// tests/acceptance/steps/steps.js file
export default function(assert) {
return steps(assert)
.then('I should find a file', function() {
assert.ok(true, this.step);
});
}

View File

@ -13,11 +13,12 @@ Feature: submit blank
And I submit And I submit
Then the url should be /datacenter/[Slug]/create Then the url should be /datacenter/[Slug]/create
Where: Where:
------------------ --------------------------
| Model | Slug | | Model | Slug |
| kv | kv | | kv | kv |
| acl | acls | | acl | acls |
------------------ | intention | intentions |
--------------------------
@ignore @ignore
Scenario: The button is disabled Scenario: The button is disabled
Then ok Then ok

View File

@ -0,0 +1,11 @@
export default function(clickable, is) {
return function(obj) {
return {
...obj,
...{
cancel: clickable('[type=reset]'),
cancelIsEnabled: is(':not(:disabled)', '[type=reset]'),
},
};
};
}

View File

@ -0,0 +1,11 @@
export default function(clickable, is) {
return function(obj) {
return {
...obj,
...{
create: clickable('[data-test-create]'),
createIsEnabled: is(':not(:disabled)', '[data-test-create]'),
},
};
};
}

View File

@ -0,0 +1,11 @@
export default function(clickable) {
return function(obj) {
return {
...obj,
...{
delete: clickable('[data-test-delete]'),
confirmDelete: clickable('button.type-delete'),
},
};
};
}

View File

@ -0,0 +1,11 @@
export default function(clickable, is) {
return function(obj) {
return {
...obj,
...{
submit: clickable('[type=submit]'),
submitIsEnabled: is(':not(:disabled)', '[type=submit]'),
},
};
};
}

View File

@ -1,27 +1,48 @@
import { create, clickable, is, attribute, collection, text } from 'ember-cli-page-object';
import { visitable } from 'consul-ui/tests/lib/page-object/visitable';
import createDeletable from 'consul-ui/tests/lib/page-object/createDeletable';
import createSubmitable from 'consul-ui/tests/lib/page-object/createSubmitable';
import createCreatable from 'consul-ui/tests/lib/page-object/createCreatable';
import createCancelable from 'consul-ui/tests/lib/page-object/createCancelable';
import page from 'consul-ui/tests/pages/components/page';
import radiogroup from 'consul-ui/tests/lib/page-object/radiogroup';
import index from 'consul-ui/tests/pages/index'; import index from 'consul-ui/tests/pages/index';
import dcs from 'consul-ui/tests/pages/dc'; import dcs from 'consul-ui/tests/pages/dc';
import settings from 'consul-ui/tests/pages/settings'; import settings from 'consul-ui/tests/pages/settings';
import catalogFilter from 'consul-ui/tests/pages/components/catalog-filter';
import services from 'consul-ui/tests/pages/dc/services/index'; import services from 'consul-ui/tests/pages/dc/services/index';
import service from 'consul-ui/tests/pages/dc/services/show'; import service from 'consul-ui/tests/pages/dc/services/show';
import nodes from 'consul-ui/tests/pages/dc/nodes/index'; import nodes from 'consul-ui/tests/pages/dc/nodes/index';
import node from 'consul-ui/tests/pages/dc/nodes/show'; import node from 'consul-ui/tests/pages/dc/nodes/show';
import kvs from 'consul-ui/tests/pages/dc/kv/index'; import kvs from 'consul-ui/tests/pages/dc/kv/index';
import kv from 'consul-ui/tests/pages/dc/kv/edit'; import kv from 'consul-ui/tests/pages/dc/kv/edit';
import aclFilter from 'consul-ui/tests/pages/components/acl-filter';
import acls from 'consul-ui/tests/pages/dc/acls/index'; import acls from 'consul-ui/tests/pages/dc/acls/index';
import acl from 'consul-ui/tests/pages/dc/acls/edit'; import acl from 'consul-ui/tests/pages/dc/acls/edit';
import intentionFilter from 'consul-ui/tests/pages/components/intention-filter';
import intentions from 'consul-ui/tests/pages/dc/intentions/index';
import intention from 'consul-ui/tests/pages/dc/intentions/edit'; import intention from 'consul-ui/tests/pages/dc/intentions/edit';
const deletable = createDeletable(clickable);
const submitable = createSubmitable(clickable, is);
const creatable = createCreatable(clickable, is);
const cancelable = createCancelable(clickable, is);
export default { export default {
index, index: create(index(visitable, collection)),
dcs, dcs: create(dcs(visitable, clickable, attribute, collection)),
settings, services: create(services(visitable, clickable, attribute, collection, page, catalogFilter)),
services, service: create(service(visitable, attribute, collection, text, catalogFilter)),
service, nodes: create(nodes(visitable, clickable, attribute, collection, catalogFilter)),
nodes, node: create(node(visitable, deletable, clickable, attribute, collection, radiogroup)),
node, kvs: create(kvs(visitable, deletable, creatable, clickable, attribute, collection)),
kvs, kv: create(kv(visitable, submitable, deletable, cancelable, clickable)),
kv, acls: create(acls(visitable, deletable, creatable, clickable, attribute, collection, aclFilter)),
acls, acl: create(acl(visitable, submitable, deletable, cancelable, clickable)),
acl, intentions: create(
intention, intentions(visitable, deletable, creatable, clickable, attribute, collection, intentionFilter)
),
intention: create(intention(visitable, submitable, deletable, cancelable)),
settings: create(settings(visitable, submitable)),
}; };

View File

@ -0,0 +1,9 @@
import { triggerable } from 'ember-cli-page-object';
import radiogroup from 'consul-ui/tests/lib/page-object/radiogroup';
export default {
...radiogroup('action', ['', 'allow', 'deny']),
...{
scope: '[data-test-intention-filter]',
search: triggerable('keypress', '[name="s"]'),
},
};

View File

@ -1,6 +1,6 @@
import { clickable } from 'ember-cli-page-object'; import { clickable } from 'ember-cli-page-object';
export default { export default {
navigation: ['services', 'nodes', 'kvs', 'acls', 'docs', 'settings'].reduce( navigation: ['services', 'nodes', 'kvs', 'acls', 'intentions', 'docs', 'settings'].reduce(
function(prev, item, i, arr) { function(prev, item, i, arr) {
const key = item; const key = item;
return Object.assign({}, prev, { return Object.assign({}, prev, {

View File

@ -1,9 +1,12 @@
import { create, visitable, attribute, collection, clickable } from 'ember-cli-page-object'; export default function(visitable, clickable, attribute, collection) {
return {
export default create({
visit: visitable('/:dc/'), visit: visitable('/:dc/'),
dcs: collection('[data-test-datacenter-picker]'), dcs: collection('[data-test-datacenter-picker]'),
showDatacenters: clickable('[data-test-datacenter-selected]'), showDatacenters: clickable('[data-test-datacenter-selected]'),
selectedDc: attribute('data-test-datacenter-selected', '[data-test-datacenter-selected]'), selectedDc: attribute('data-test-datacenter-selected', '[data-test-datacenter-selected]'),
selectedDatacenter: attribute('data-test-datacenter-selected', '[data-test-datacenter-selected]'), selectedDatacenter: attribute(
}); 'data-test-datacenter-selected',
'[data-test-datacenter-selected]'
),
};
}

View File

@ -1,11 +1,11 @@
import { create, clickable, triggerable, is } from 'ember-cli-page-object'; export default function(visitable, submitable, deletable, cancelable, clickable) {
import { visitable } from 'consul-ui/tests/lib/page-object/visitable'; return submitable(
cancelable(
export default create({ deletable({
// custom visitable
visit: visitable(['/:dc/acls/:acl', '/:dc/acls/create']), visit: visitable(['/:dc/acls/:acl', '/:dc/acls/create']),
// fillIn: fillable('input, textarea, [contenteditable]'), use: clickable('[data-test-use]'),
name: triggerable('keypress', '[name="name"]'), confirmUse: clickable('button.type-delete'),
submit: clickable('[type=submit]'), })
submitIsEnabled: is(':not(:disabled)', '[type=submit]'), )
}); );
}

View File

@ -1,14 +1,16 @@
import { create, visitable, collection, attribute, clickable } from 'ember-cli-page-object'; export default function(visitable, deletable, creatable, clickable, attribute, collection, filter) {
return creatable({
import filter from 'consul-ui/tests/pages/components/acl-filter';
export default create({
visit: visitable('/:dc/acls'), visit: visitable('/:dc/acls'),
acls: collection('[data-test-tabular-row]', { acls: collection(
'[data-test-tabular-row]',
deletable({
name: attribute('data-test-acl', '[data-test-acl]'), name: attribute('data-test-acl', '[data-test-acl]'),
acl: clickable('a'), acl: clickable('a'),
actions: clickable('label'), actions: clickable('label'),
delete: clickable('[data-test-delete]'), use: clickable('[data-test-use]'),
confirmDelete: clickable('button.type-delete'), confirmUse: clickable('button.type-delete'),
}), })
),
filter: filter, filter: filter,
}); });
}

View File

@ -1,8 +1,9 @@
import { create, clickable } from 'ember-cli-page-object'; export default function(visitable, submitable, deletable, cancelable) {
import { visitable } from 'consul-ui/tests/lib/page-object/visitable'; return submitable(
cancelable(
export default create({ deletable({
// custom visitable
visit: visitable(['/:dc/intentions/:intention', '/:dc/intentions/create']), visit: visitable(['/:dc/intentions/:intention', '/:dc/intentions/create']),
submit: clickable('[type=submit]'), })
}); )
);
}

View File

@ -0,0 +1,19 @@
export default function(visitable, deletable, creatable, clickable, attribute, collection, filter) {
return creatable({
visit: visitable('/:dc/intentions'),
intentions: collection(
'[data-test-tabular-row]',
deletable({
source: attribute('data-test-intention-source', '[data-test-intention-source]'),
destination: attribute(
'data-test-intention-destination',
'[data-test-intention-destination]'
),
action: attribute('data-test-intention-action', '[data-test-intention-action]'),
intention: clickable('a'),
actions: clickable('label'),
})
),
filter: filter,
});
}

View File

@ -1,11 +1,9 @@
import { create, clickable, is } from 'ember-cli-page-object'; export default function(visitable, submitable, deletable, cancelable) {
import { visitable } from 'consul-ui/tests/lib/page-object/visitable'; return submitable(
cancelable(
export default create({ deletable({
// custom visitable
visit: visitable(['/:dc/kv/:kv/edit', '/:dc/kv/create'], str => str), visit: visitable(['/:dc/kv/:kv/edit', '/:dc/kv/create'], str => str),
// fillIn: fillable('input, textarea, [contenteditable]'), })
// name: triggerable('keypress', '[name="additional"]'), )
submit: clickable('[type=submit]'), );
submitIsEnabled: is(':not(:disabled)', '[type=submit]'), }
});

View File

@ -1,12 +1,13 @@
import { create, visitable, collection, attribute, clickable } from 'ember-cli-page-object'; export default function(visitable, deletable, creatable, clickable, attribute, collection) {
return creatable({
export default create({
visit: visitable('/:dc/kv'), visit: visitable('/:dc/kv'),
kvs: collection('[data-test-tabular-row]', { kvs: collection(
'[data-test-tabular-row]',
deletable({
name: attribute('data-test-kv', '[data-test-kv]'), name: attribute('data-test-kv', '[data-test-kv]'),
kv: clickable('a'), kv: clickable('a'),
actions: clickable('label'), actions: clickable('label'),
delete: clickable('[data-test-delete]'), })
confirmDelete: clickable('button.type-delete'), ),
}),
}); });
}

View File

@ -1,11 +1,10 @@
import { create, visitable, collection, attribute, clickable } from 'ember-cli-page-object'; export default function(visitable, clickable, attribute, collection, filter) {
import filter from 'consul-ui/tests/pages/components/catalog-filter'; return {
export default create({
visit: visitable('/:dc/nodes'), visit: visitable('/:dc/nodes'),
nodes: collection('[data-test-node]', { nodes: collection('[data-test-node]', {
name: attribute('data-test-node'), name: attribute('data-test-node'),
node: clickable('header a'), node: clickable('header a'),
}), }),
filter: filter, filter: filter,
}); };
}

View File

@ -1,7 +1,5 @@
import { create, visitable, collection, attribute } from 'ember-cli-page-object'; export default function(visitable, deletable, clickable, attribute, collection, radiogroup) {
return {
import radiogroup from 'consul-ui/tests/lib/page-object/radiogroup';
export default create({
visit: visitable('/:dc/nodes/:node'), visit: visitable('/:dc/nodes/:node'),
tabs: radiogroup('tab', ['health-checks', 'services', 'round-trip-time', 'lock-sessions']), tabs: radiogroup('tab', ['health-checks', 'services', 'round-trip-time', 'lock-sessions']),
healthchecks: collection('[data-test-node-healthcheck]', { healthchecks: collection('[data-test-node-healthcheck]', {
@ -10,7 +8,11 @@ export default create({
services: collection('#services [data-test-tabular-row]', { services: collection('#services [data-test-tabular-row]', {
port: attribute('data-test-service-port', '.port'), port: attribute('data-test-service-port', '.port'),
}), }),
sessions: collection('#lock-sessions [data-test-tabular-row]', { sessions: collection(
'#lock-sessions [data-test-tabular-row]',
deletable({
TTL: attribute('data-test-session-ttl', '[data-test-session-ttl]'), TTL: attribute('data-test-session-ttl', '[data-test-session-ttl]'),
}), })
}); ),
};
}

View File

@ -1,9 +1,5 @@
import { create, visitable, collection, attribute, clickable } from 'ember-cli-page-object'; export default function(visitable, clickable, attribute, collection, page, filter) {
return {
import page from 'consul-ui/tests/pages/components/page';
import filter from 'consul-ui/tests/pages/components/catalog-filter';
export default create({
visit: visitable('/:dc/services'), visit: visitable('/:dc/services'),
services: collection('[data-test-service]', { services: collection('[data-test-service]', {
name: attribute('data-test-service'), name: attribute('data-test-service'),
@ -11,6 +7,6 @@ export default create({
}), }),
dcs: collection('[data-test-datacenter-picker]'), dcs: collection('[data-test-datacenter-picker]'),
navigation: page.navigation, navigation: page.navigation,
filter: filter, filter: filter,
}); };
}

View File

@ -1,7 +1,5 @@
import { create, visitable, collection, attribute, text } from 'ember-cli-page-object'; export default function(visitable, attribute, collection, text, filter) {
import filter from 'consul-ui/tests/pages/components/catalog-filter'; return {
export default create({
visit: visitable('/:dc/services/:service'), visit: visitable('/:dc/services/:service'),
nodes: collection('[data-test-node]', { nodes: collection('[data-test-node]', {
name: attribute('data-test-node'), name: attribute('data-test-node'),
@ -15,4 +13,5 @@ export default create({
address: text('header strong'), address: text('header strong'),
}), }),
filter: filter, filter: filter,
}); };
}

View File

@ -1,6 +1,6 @@
import { create, visitable, collection } from 'ember-cli-page-object'; export default function(visitable, collection) {
return {
export default create({
visit: visitable('/'), visit: visitable('/'),
dcs: collection('[data-test-datacenter-list]'), dcs: collection('[data-test-datacenter-list]'),
}); };
}

View File

@ -1,6 +1,5 @@
import { create, visitable, clickable } from 'ember-cli-page-object'; export default function(visitable, submitable) {
return submitable({
export default create({
visit: visitable('/settings'), visit: visitable('/settings'),
submit: clickable('[type=submit]'),
}); });
}

View File

@ -5,6 +5,8 @@ import getDictionary from '@hashicorp/ember-cli-api-double/dictionary';
import pages from 'consul-ui/tests/pages'; import pages from 'consul-ui/tests/pages';
import api from 'consul-ui/tests/helpers/api'; import api from 'consul-ui/tests/helpers/api';
// const dont = `( don't| shouldn't| can't)?`;
const create = function(number, name, value) { const create = function(number, name, value) {
// don't return a promise here as // don't return a promise here as
// I don't need it to wait // I don't need it to wait
@ -83,6 +85,15 @@ export default function(assert) {
.when('I click "$selector"', function(selector) { .when('I click "$selector"', function(selector) {
return click(selector); return click(selector);
}) })
// TODO: Probably nicer to think of better vocab than having the 'without " rule'
.when('I click (?!")$property(?!")', function(property) {
try {
return currentPage[property]();
} catch (e) {
console.error(e);
throw new Error(`The '${property}' property on the page object doesn't exist`);
}
})
.when('I click $prop on the $component', function(prop, component) { .when('I click $prop on the $component', function(prop, component) {
// Collection // Collection
var obj; var obj;
@ -240,7 +251,9 @@ export default function(assert) {
assert.equal(len, num, `Expected ${num} ${model}s, saw ${len}`); assert.equal(len, num, `Expected ${num} ${model}s, saw ${len}`);
}) })
.then(['I see $num $model model with the $property "$value"'], function( // TODO: I${ dont } see
.then([`I see $num $model model[s]? with the $property "$value"`], function(
// negate,
num, num,
model, model,
property, property,

View File

@ -82,8 +82,8 @@
js-yaml "^3.10.0" js-yaml "^3.10.0"
"@hashicorp/consul-api-double@^1.2.0": "@hashicorp/consul-api-double@^1.2.0":
version "1.2.0" version "1.3.0"
resolved "https://registry.yarnpkg.com/@hashicorp/consul-api-double/-/consul-api-double-1.2.0.tgz#2cd2a991818e13e7b97803af3d62ec6c9cb83b28" resolved "https://registry.yarnpkg.com/@hashicorp/consul-api-double/-/consul-api-double-1.3.0.tgz#fded48ca4db1e63c66e39b4433b2169b6add69ed"
"@hashicorp/ember-cli-api-double@^1.3.0": "@hashicorp/ember-cli-api-double@^1.3.0":
version "1.3.0" version "1.3.0"