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

#234 | Better URL validation | Iframe board tests added (plus some refactor) #242

Merged
merged 7 commits into from
Jan 24, 2020
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->

- [ ] My code follows the [code style](/CONTRIBUTING.md#coding-conventions) of this project.
- [ ] My code follows the [code style](https://github.com/Cognifide/cogboard/blob/master/CONTRIBUTING.md#coding-conventions) of this project.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This link did not worked

- [ ] My change requires a change to the documentation.
- [ ] Automated functional tests have been added or modified to cover my changes (if applicable)
- [ ] I have updated the documentation accordingly.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@ import io.vertx.core.eventbus.MessageConsumer
import io.vertx.core.json.JsonObject

class ControllerFactory {
fun create(address: String, vertx: Vertx, configuration: Map<String, (JsonObject) -> String>): MessageConsumer<JsonObject> {
return vertx.eventBus()
.consumer<JsonObject>(address)
.handler {
val body = it.body()
configuration[body.getString("method")]?.let { method ->
it.reply(method(body.getJsonObject("payload")))
}
fun create(
address: String,
vertx: Vertx,
configuration: Map<String, (JsonObject) -> String>
): MessageConsumer<JsonObject> = vertx.eventBus()
.consumer<JsonObject>(address)
.handler {
val body = it.body()
configuration[body.getString("method")]?.let { method ->
it.reply(method(body.getJsonObject("payload")))
Comment on lines +8 to +17
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Detekt fix

}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,17 @@ fun <T> List<T>.getNextListIndex(currentIndex: Int): Int = when {
}

fun <T> List<T>.getRandomListIndex(usedIndexes: List<Int>): Int {

if (this.isEmpty()) {
return -1
}

val indexes = this.mapIndexed { index, _ -> index }
.filter { i -> !usedIndexes.contains(i) }

// If there is one index, there is no need to use random function
if (indexes.size == 1) {
return indexes[0]
}

return if (indexes.isNotEmpty()) {
indexes[Random.nextInt(0, indexes.size)]
return if (this.isEmpty()) {
-1
} else {
Random.nextInt(0, this.size)
val indexes = this.mapIndexed { index, _ -> index }
.filter { i -> !usedIndexes.contains(i) }
when {
// If there is one index, there is no need to use random function
indexes.size == 1 -> return indexes[0]
indexes.isNotEmpty() -> indexes[Random.nextInt(0, indexes.size)]
else -> Random.nextInt(0, this.size)
}
Comment on lines +15 to +25
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Detekt fix

}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,10 @@ class SonarQubeWidget(vertx: Vertx, config: JsonObject) : AsyncWidget(vertx, con
metrics.list
.stream()
.map { it as JsonObject }
.filter { it.getString(version.getMetricKey()) != "alert_status" && it.getString(version.getMetricKey()) == metricName }
.filter {
it.getString(version.getMetricKey()) != "alert_status" &&
it.getString(version.getMetricKey()) == metricName
}
Comment on lines +63 to +66
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Detekt fix

.findFirst()
.ifPresent { result.put(metricName, version.getMetricValue(it)) }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,8 @@ interface Version {
fun getMetricValue(metric: JsonObject): Int

companion object Test {
fun getVersion(version: String): Version {
if (version.equals("5.x"))
return V5x()
else
return V7x()
}
fun getVersion(version: String) =
if (version == "5.x") V5x()
else V7x()
Comment on lines +18 to +20
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Detekt fix

}
}
18 changes: 15 additions & 3 deletions cogboard-webapp/src/components/widgets/dialogFields/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,11 @@ const dialogFields = {
component: TextInput,
name: 'publicUrl',
label: 'Public URL',
validator: () => string().url(vm.INVALID_URL())
validator: () =>
string().matches(
/^(?:([A-Za-z]+):)?(\/{0,3})([0-9.\-A-Za-z]+)(?::(\d+))?(?:\/([^?#]*))?(?:\?([^#]*))?(?:#(.*))?$/,
{ message: vm.INVALID_URL(), excludeEmptyString: true }
)
Comment on lines +79 to +83
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better URL Validation - port number possible

},
WidgetTypeField: {
component: DisplayValueSelect,
Expand Down Expand Up @@ -210,13 +214,21 @@ const dialogFields = {
component: TextInput,
name: 'url',
label: 'URL',
validator: () => string().url(vm.INVALID_URL())
validator: () =>
string().matches(
/^(?:([A-Za-z]+):)?(\/{0,3})([0-9.\-A-Za-z]+)(?::(\d+))?(?:\/([^?#]*))?(?:\?([^#]*))?(?:#(.*))?$/,
{ message: vm.INVALID_URL(), excludeEmptyString: true }
)
Comment on lines +217 to +221
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better URL Validation - port number possible

},
IFrameURL: {
component: TextInput,
name: 'iframeUrl',
label: 'URL',
validator: () => string().url(vm.INVALID_URL())
validator: () =>
string().matches(
/^(?:([A-Za-z]+):)?(\/{0,3})([0-9.\-A-Za-z]+)(?::(\d+))?(?:\/([^?#]*))?(?:\?([^#]*))?(?:#(.*))?$/,
{ message: vm.INVALID_URL(), excludeEmptyString: true }
)
Comment on lines +227 to +231
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better URL Validation - port number possible

},
IdString: {
component: TextInput,
Expand Down
2 changes: 1 addition & 1 deletion functional/cypress-tests/cypress/fixtures/Dashboard.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export function dashboardNameGen(name = 'Dashboard') {
return `name_${Date.now().toString()}`;
return `${name}_${Date.now().toString()}`;
}

export const columnEdgeValues = ['3', '4', '20', '21'];
Expand Down
87 changes: 47 additions & 40 deletions functional/cypress-tests/cypress/integration/dashboards.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@ import {
dashboardNameGen,
columnEdgeValues,
switchIntervalEdgeValues,
dashboardNames,
dashboardTypes
dashboardNames
} from '../fixtures/Dashboard';
import { addWidgetsDashboard } from '../support/dashboard';
import { addIframeDashboard, addWidgetsDashboard } from '../support/dashboard';

describe('Basic Dashboard CRUD', () => {
const newTitle = dashboardNameGen('Edit');
Expand All @@ -15,14 +14,24 @@ describe('Basic Dashboard CRUD', () => {
cy.login();
});

it('Logged user can add new dashboard', () => {
it('Logged user can add new widgets dashboard', () => {
addWidgetsDashboard();
});

it('Logged user can choose dashboard', () => {
it('Logged user can choose widgets dashboard', () => {
addWidgetsDashboard().canBeSelected();
});

it('Logged user can add new iframe dashboard', () => {
addIframeDashboard();
});

it('Logged user can choose iframe dashboard', () => {
addIframeDashboard()
.canBeSelected()
.assertIframeExists();
});
Comment on lines +25 to +33
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added tests for Iframe widget


it('Anonymous user can choose dashboard', () => {
const board = addWidgetsDashboard();
cy.closeDrawer();
Expand All @@ -46,63 +55,61 @@ describe('Basic Dashboard CRUD', () => {
});
});

describe('Dashboard Frontend Validation', () => {
describe('Dashboard Input Validation', () => {
beforeEach(() => {
cy.visit('/');
cy.login();
});

it(' For empty dashboard name is displayed and submit is impossible', () => {
addWidgetsDashboard(' ', '4', '10', true).assertErrorMessageVisible(
'This field is required'
);
it('Name input do not accept empty strings', () => {
addWidgetsDashboard(' ')
.expectConfigToBeInvalid()
.assertErrorMessageVisible('This field is required');
});

dashboardNames.forEach(value => {
it(` For too long dashboard name is displayed and submit is impossible. Length: ${value.length}`, () => {
const board = addWidgetsDashboard(
value,
dashboardTypes.widgets,
'8',
'10',
true
);
it(`Name input accepts strings not exceeding 50 characters. Tested value: ${value.length}`, () => {
const board = addWidgetsDashboard(value);
if (value.length > 50) {
board.assertErrorMessageVisible(
'Title length must be less or equal to 50.'
);
board
.expectConfigToBeInvalid()
.assertErrorMessageVisible(
'Title length must be less or equal to 50.'
);
} else {
board.assertErrorNotVisible();
board.expectConfigToBeValid();
}
});
});

columnEdgeValues.forEach(value => {
it(` For Columns input is displayed and submit is impossible for incorrect values. Edge value : ${value}`, () => {
const board = addWidgetsDashboard(undefined, value, '10', true);
if (value === '3') {
board.assertErrorMessageVisible(
'Columns number cannot be less than 4.'
);
} else if (value === '21') {
board.assertErrorMessageVisible(
'Columns number cannot be more than 20.'
);
it(`Columns input accepts only values from 4 to 20. Tested value: ${value}`, () => {
const board = addWidgetsDashboard(undefined, value);
if (value < 4) {
board
.expectConfigToBeInvalid()
.assertErrorMessageVisible('Columns number cannot be less than 4.');
} else if (value > 20) {
board
.expectConfigToBeInvalid()
.assertErrorMessageVisible('Columns number cannot be more than 20.');
} else {
board.assertErrorNotVisible();
board.expectConfigToBeValid();
}
});
});

switchIntervalEdgeValues.forEach(value => {
it(` For Switch Interval input is displayed and submit is impossible for incorrect values. Edge value: ${value}`, () => {
const board = addWidgetsDashboard(undefined, '8', value, true);
if (value === '2') {
board.assertErrorMessageVisible(
'Switch interval number cannot be less than 3.'
);
it(`Switch interval input accepts only values grater than 2. Tested value: ${value}`, () => {
const board = addWidgetsDashboard(undefined, undefined, value);
if (value < 3) {
board
.expectConfigToBeInvalid()
.assertErrorMessageVisible(
'Switch interval number cannot be less than 3.'
);
} else {
board.assertErrorNotVisible();
board.expectConfigToBeValid();
}
});
});
Expand Down
59 changes: 22 additions & 37 deletions functional/cypress-tests/cypress/support/dashboard.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
import { dashboardNameGen, dashboardTypes } from '../fixtures/Dashboard';

class Dashboard {
constructor(
name = dashboardNameGen(),
type,
columns,
switchInterval,
expectedFailure
) {
constructor(name = dashboardNameGen(), type, columns, switchInterval) {
this.name = name;
cy.addDashboard(this.name, columns, switchInterval, expectedFailure, type);
cy.addDashboard(this.name, columns, switchInterval, type);
}

canBeSelected() {
Expand All @@ -18,6 +12,11 @@ class Dashboard {
return this;
}

assertIframeExists() {
cy.get('iframe').should('is.visible');
return this;
}

openEditDialog() {
cy.contains('[data-cy="board-card"]', this.name)
.find('[data-cy="board-card-edit-button"]')
Expand Down Expand Up @@ -65,13 +64,21 @@ class Dashboard {
cy.contains('[data-cy="board-card"]', this.name).should('not.exist');
}

assertErrorNotVisible() {
assertErrorMessageVisible(message) {
cy.contains('[data-cy^="board-form-"]', message).should('is.visible');
return this;
}

expectConfigToBeValid() {
cy.contains('[data-cy="board-card"]', this.name)
.scrollIntoView()
.should('is.visible');
cy.get('[data-cy="board-form-title-input-error"]').should('not.visible');
return this;
}

assertErrorMessageVisible(message) {
cy.contains('[data-cy^="board-form-"]', message).should('is.visible');
expectConfigToBeInvalid() {
cy.contains('h2', 'Add new board').should('is.visible');
return this;
}

Expand All @@ -81,32 +88,10 @@ class Dashboard {
}
}

export function addWidgetsDashboard(
name,
columns,
switchInterval,
expectedFailure
) {
return new Dashboard(
name,
dashboardTypes.widgets,
columns,
switchInterval,
expectedFailure
);
export function addWidgetsDashboard(name, columns, switchInterval) {
return new Dashboard(name, dashboardTypes.widgets, columns, switchInterval);
}

export function addIframeDashboard(
name,
columns,
switchInterval,
expectedFailure
) {
return new Dashboard(
name,
dashboardTypes.iframe,
columns,
switchInterval,
expectedFailure
);
export function addIframeDashboard(name, columns, switchInterval) {
return new Dashboard(name, dashboardTypes.iframe, columns, switchInterval);
}
Loading