Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed #616 #627

Merged
merged 5 commits into from
Dec 18, 2017
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,21 @@ Say you want to run FlowRunnerTest.
$ ./gradlew -Dtest.single=FlowRunner test
```

Make sure that all tests pass. Please, do not submit patches that fail.
If you want to run just the Quick-Start UI End to End tests, you will need nodejs 8.9.1 or later installed:
```jshelllanguage
cd quick-start
npm install
npm install -g protractor
npm run webdriver-update
npm run e2e
```
*Note for e2e tests, the datahub must be running and so must a MarkLogic instance with appservers for 8010-8014 free.*

For those that want to run the E2E tests from Intellij or another IDE to fullstack debug you can have add a run/debug
task that runs the script "e2e". Make sure to add a 'before launch' task as folows: npm run "webdriver-update".


**Make sure that all tests pass. Please, do not submit patches that fail.**

#### Push your changes

Expand Down
118 changes: 117 additions & 1 deletion quick-start/e2e/page-objects/entities/entities.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { protractor, browser, element, by, By, $, $$, ExpectedConditions as EC } from 'protractor'
import {
protractor, browser, element, by, By, $, $$, ExpectedConditions as EC, ElementFinder,
ElementArrayFinder
} from 'protractor'
import { AppPage } from '../appPage';
import { pages } from '../page';
import {Element} from "@angular/compiler";

export class EntityPage extends AppPage {

Expand Down Expand Up @@ -41,6 +45,118 @@ export class EntityPage extends AppPage {
return element(by.css('.toolbar #delete-property'));
}

get confirmDialog() {
return element(by.tagName('mdl-dialog-component'));
}

get confirmDialogYesButton(){
return element(by.buttonText('Yes'));
}

get confirmDialogNoButton(){
return element(by.buttonText('No'));
}

get getProperties() {
return element(by.css('.properties > tBody > tr'));
}

get lastProperty() {
return element.all(by.css('.properties > tBody > tr')).last();
}

getPropertyByPosition(position: number){
return element.all(by.css('.properties > tBody > tr:nth-child('+position+')'));
}

getPropertyColumn(property: ElementFinder, column: number){
return property.element(by.css('td:nth-child('+column+') > :first-child'));
}

getPropertyCheckBox(property: ElementFinder){
return property.element(by.css('td:nth-child(1) > input[type="checkbox"]'));
}

getPropertyPrimaryKey(property: ElementFinder){
return property.element(by.css('td:nth-child(2) > i'));
}

getPropertyRangeIndex(property: ElementFinder){
return property.element(by.css('td:nth-child(3) > i'));
}

getPropertyPathRange(property: ElementFinder){
return property.element(by.css('td:nth-child(4) > i'));
}

getPropertyWordLexicon(property: ElementFinder){
return property.element(by.css('td:nth-child(5) > i'));
}

getPropertyRequired(property: ElementFinder){
return property.element(by.css('td:nth-child(6) > i'));
}

getPropertyName(property: ElementFinder){
return property.element(by.css('td:nth-child(7) > input[type="text"]'));
}

getPropertyType(property: ElementFinder){
return property.element(by.css('td:nth-child(8) > select'));
}

getPropertyCardinality(property: ElementFinder){
return property.element(by.css('td:nth-child(9) > select'));
}

getPropertyDescription(property: ElementFinder){
return property.element(by.css('td:nth-child(10) > input[type="text"]'));
}

getPropertyCheckBoxColumn(property: ElementFinder){
return property.element(by.css('td:nth-child(1)'));
}

getPropertyPrimaryKeyColumn(property: ElementFinder){
return property.element(by.css('td:nth-child(2)'));
}

getPropertyRangeIndexColumn(property: ElementFinder){
return property.element(by.css('td:nth-child(3)'));
}

getPropertyPathRangeColumn(property: ElementFinder){
return property.element(by.css('td:nth-child(4)'));
}

getPropertyWordLexiconColumn(property: ElementFinder){
return property.element(by.css('td:nth-child(5)'));
}

getPropertyRequiredColumn(property: ElementFinder){
return property.element(by.css('td:nth-child(6)'));
}

getPropertyNameColumn(property: ElementFinder){
return property.element(by.css('td:nth-child(7)'));
}

getPropertyTypeColumn(property: ElementFinder){
return property.element(by.css('td:nth-child(8)'));
}

getPropertyCardinalityColumn(property: ElementFinder){
return property.element(by.css('td:nth-child(9)'));
}

getPropertyDescriptionColumn(property: ElementFinder){
return property.element(by.css('td:nth-child(10)'));
}

get editEntityButton(){
return element(by.css('.edit-start > i'));
}

get saveEntity() {
return element(by.buttonText('Save'));
}
Expand Down
8 changes: 8 additions & 0 deletions quick-start/e2e/page-objects/page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@ abstract class Page {
})
}

//checks if an element has a class or not, useful throughout
//boolean output
hasClass(element, cls) {
return element.getAttribute('class').then(function (classes) {
return classes.split(' ').indexOf(cls) !== -1;
})
}

//https://github.com/angular/protractor/issues/2019
sendKeys(field, str) {
if (pages.browserName === 'chrome' || pages.browserName === 'internet explorer') {
Expand Down
98 changes: 96 additions & 2 deletions quick-start/e2e/specs/create/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import loginPage from '../../page-objects/auth/login';
import dashboardPage from '../../page-objects/dashboard/dashboard';
import entityPage from '../../page-objects/entities/entities';
import flowPage from '../../page-objects/flows/flows';
import {assertNotNull} from "@angular/compiler/src/output/output_ast";

export default function() {
describe('create entities', () => {
Expand Down Expand Up @@ -67,8 +68,7 @@ export default function() {
dashboardPage.clearDatabases.click();
browser.wait(EC.elementToBeClickable(dashboardPage.clearButton));
dashboardPage.clearButton.click();

// wait for all four to be 0
//wait for all four to be 0
browser.wait(dashboardPage.zeroCounts.count().then((count) => {
return count === 4;
}));
Expand All @@ -85,7 +85,101 @@ export default function() {
expect(entityPage.entityEditor.isPresent()).toBe(true);
entityPage.entityTitle.sendKeys('TestEntity');
entityPage.saveEntity.click();
browser.wait(EC.visibilityOf(entityPage.getEntityBox('TestEntity')));
expect(entityPage.getEntityBox('TestEntity').isDisplayed()).toBe(true);
entityPage.toolsButton.click();
});

//TODO: refactor out these create tests into specific tests
//Here we're placing the create properties and remote properties along with index setting tests
//These should probably be moved to specific tests files for each 'thing' entities, flow,
// after the general create script and before the general tear down scripts

it('should create a new property', function(){
browser.actions().mouseMove(element(by.tagName('body')), {x:314, y:176}).click().perform();
browser.wait(EC.visibilityOf(entityPage.entityEditor));
expect(entityPage.entityEditor.isPresent()).toBe(true);
//tell the UI to add the visual row
entityPage.addProperty.click();
//now compare to see if the current count is 1
element.all(by.css('.properties > table > tBody > tr')).count().then(function(props){expect(props === 1)});

//select the last (or first if only 1) property
let lastProperty = entityPage.lastProperty;
expect(lastProperty.isPresent() && lastProperty.isDisplayed());
//populate the fields for name, range index, type, and description
entityPage.getPropertyName(lastProperty).sendKeys("test");
entityPage.getPropertyRangeIndexColumn(lastProperty).click();
entityPage.getPropertyType(lastProperty).element(by.cssContainingText('option', 'string')).click();
entityPage.getPropertyDescription(lastProperty).sendKeys("this is a test property");
//let's see if our values hold!
expect(entityPage.getPropertyName(lastProperty).getAttribute('value')).toEqual("test");
expect(entityPage.hasClass(entityPage.getPropertyRangeIndex(lastProperty), 'active')).toBe(true);
expect(entityPage.getPropertyType(lastProperty).getAttribute('value')).toEqual("24: string");
expect(entityPage.getPropertyDescription(lastProperty).getAttribute('value')).toEqual("this is a test property");
//let's add 1 more so we can remove one for the next test
entityPage.addProperty.click();
//repoint last property to the new last property
lastProperty = entityPage.lastProperty;
expect(lastProperty.isPresent() && lastProperty.isDisplayed());
//populate the fields for name, range index, type, and description
entityPage.getPropertyName(lastProperty).sendKeys("ID");
entityPage.getPropertyPrimaryKeyColumn(lastProperty).click();
entityPage.getPropertyType(lastProperty).element(by.cssContainingText('option', 'integer')).click();
entityPage.getPropertyDescription(lastProperty).sendKeys("this is our primary key");


//let's save it now that it's populated
entityPage.saveEntity.click();
browser.wait(EC.elementToBeClickable(entityPage.confirmDialogNoButton));
expect(entityPage.confirmDialogNoButton.isPresent()).toBe(true);
entityPage.confirmDialogNoButton.click();
});

it('should remove a property', function(){
//now time to delete, let's reopen the editor
browser.actions().mouseMove(element(by.tagName('body')), {x:314, y:176}).click().perform();
browser.wait(EC.visibilityOf(entityPage.entityEditor));
expect(entityPage.entityEditor.isPresent()).toBe(true);
//let's grab the count of the rows before we add so we can compare
element.all(by.css('.properties > table > tBody > tr')).count().then(function(props){expect(props === 2)});
let lastProperty = entityPage.lastProperty;
expect(lastProperty.isPresent() && lastProperty.isDisplayed());
entityPage.getPropertyCheckBox(lastProperty).click();
entityPage.deleteProperty.click();
browser.wait(EC.visibilityOf(entityPage.confirmDialogYesButton));
expect(entityPage.confirmDialogYesButton.isPresent()).toBe(true);
entityPage.confirmDialogYesButton.click();
element.all(by.css('.properties > table > tBody > tr')).count().then(function(props){expect(props === 1)});
//let's save it now that it's populated
entityPage.saveEntity.click();
browser.wait(EC.elementToBeClickable(entityPage.confirmDialogNoButton));
expect(entityPage.confirmDialogNoButton.isPresent()).toBe(true);
entityPage.confirmDialogNoButton.click();
});

it('should retain settings on remaining property', function() {
//now let's confirm we didn't lose any settings, reopen editor
browser.actions().mouseMove(element(by.tagName('body')), {x:314, y:176}).click().perform();
browser.wait(EC.visibilityOf(entityPage.entityEditor));
expect(entityPage.entityEditor.isPresent()).toBe(true);
//Do we still have 1 property left?
element.all(by.css('.properties > table > tBody > tr')).count().then(function(props){expect(props === 1)});
//if so, grab it
let lastProperty = entityPage.lastProperty;
expect(lastProperty.isPresent() && lastProperty.isDisplayed());
//now let's compare them with our original tests to make sure the values are equal
//let's see if our values hold!
expect(entityPage.getPropertyName(lastProperty).getAttribute('value')).toEqual("test");
expect(entityPage.hasClass(entityPage.getPropertyRangeIndex(lastProperty), 'active')).toBe(true);
expect(entityPage.getPropertyType(lastProperty).getAttribute('value')).toEqual("24: string");
expect(entityPage.getPropertyDescription(lastProperty).getAttribute('value')).toEqual("this is a test property");
//if so, great, we're done!
//so let's save this and go on with the other tests
entityPage.saveEntity.click();
browser.wait(EC.elementToBeClickable(entityPage.confirmDialogNoButton));
expect(entityPage.confirmDialogNoButton.isPresent()).toBe(true);
entityPage.confirmDialogNoButton.click();
});

it ('should go to the flow page', function() {
Expand Down
4 changes: 2 additions & 2 deletions quick-start/e2e/specs/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ describe('QuickStart', function () {
jasmine.addMatchers(CUSTOM_MATCHERS)

let yargs = require('yargs').argv
let width = typeof yargs.width === 'number' ? yargs.width : 1280
let height = typeof yargs.height === 'number' ? yargs.height : 900
let width = typeof yargs.width === 'number' ? yargs.width : 1920
let height = typeof yargs.height === 'number' ? yargs.height : 1080

request({
url: `http://localhost:8080/api/projects/reset`
Expand Down
3 changes: 2 additions & 1 deletion quick-start/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
"build.prod": "npm run clean.dist && ng build -prod",
"test": "ng test",
"lint": "ng lint",
"e2e": "./node_modules/.bin/ng e2e --proxy-config proxy.config.json"
"e2e": "./node_modules/.bin/ng e2e --proxy-config proxy.config.json",
"webdriver-update": "webdriver-manager update"
},
"private": true,
"dependencies": {
Expand Down
2 changes: 1 addition & 1 deletion quick-start/protractor.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ exports.config = {
capabilities: {
'browserName': 'chrome',
chromeOptions: {
args: [ "--headless", "--disable-gpu", "--window-size=1280,900" ]
args: ["--window-size=1920,1080" ]
}
},
directConnect: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,25 +175,28 @@ export class EntityEditorComponent {
let result = this.dialogService.confirm('Really delete the selected properties?', 'No', 'Yes');
result.subscribe(() => {
this.entity.definition.properties.forEach((value: PropertyType) => {
if (this.entity.definition.primaryKey === value.name) {
this.entity.definition.primaryKey = null;
//let's check to make sure we're only matching against the selected properties
if(value.selected) {
if (this.entity.definition.primaryKey === value.name) {
this.entity.definition.primaryKey = null;
}

_.remove(this.entity.definition.elementRangeIndex, (index: string) => {
return (index === value.name);
});

_.remove(this.entity.definition.rangeIndex, (index: string) => {
return (index === value.name);
});

_.remove(this.entity.definition.required, (index: string) => {
return (index === value.name);
});

_.remove(this.entity.definition.wordLexicon, (index: string) => {
return (index === value.name);
});
}

_.remove(this.entity.definition.elementRangeIndex, (index: string) => {
return (index === value.name);
});

_.remove(this.entity.definition.rangeIndex, (index: string) => {
return (index === value.name);
});

_.remove(this.entity.definition.required, (index: string) => {
return (index === value.name);
});

_.remove(this.entity.definition.wordLexicon, (index: string) => {
return (index === value.name);
});
});

_.remove(this.entity.definition.properties, (prop: PropertyType) => {
Expand Down