Skip to content

Commit

Permalink
console: Add gateway location tests
Browse files Browse the repository at this point in the history
  • Loading branch information
asmulko committed Feb 8, 2021
1 parent b335c26 commit fd5cd8d
Show file tree
Hide file tree
Showing 7 changed files with 274 additions and 11 deletions.
121 changes: 121 additions & 0 deletions cypress/integration/console/gateways/location/create.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
// Copyright © 2021 The Things Network Foundation, The Things Industries B.V.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

describe('Gateway location create', () => {
const gatewayId = 'test-gateway-location'
const gateway = { ids: { gateway_id: gatewayId } }
const coordinates = {
latitude: 56.95,
longitude: 24.11,
altitude: 0,
}
const userId = 'create-gateway-location-test-user'
const user = {
ids: { user_id: userId },
primary_email_address: '[email protected]',
password: 'ABCDefg123!',
password_confirm: 'ABCDefg123!',
}

before(() => {
cy.dropAndSeedDatabase()
cy.createUser(user)
cy.loginConsole({ user_id: user.ids.user_id, password: user.password })
cy.createGateway(gateway, userId)
})

beforeEach(() => {
cy.loginConsole({ user_id: user.ids.user_id, password: user.password })
})

it('displays UI elements in place', () => {
cy.visit(`${Cypress.config('consoleRootPath')}/gateways/${gatewayId}/location`)

cy.findByText('Location', { selector: 'h1' }).should('be.visible')
cy.findByText('Gateway antenna location settings', { selector: 'h3' }).should('be.visible')
cy.findByLabelText('Privacy').should('be.visible')
cy.findDescriptionByLabelText('Privacy')
.should('contain', 'The location of this gateway may be publicly displayed')
.and('be.visible')
cy.findByLabelText('Location source').should('be.visible')
cy.findDescriptionByLabelText('Location source')
.should('contain', 'Update the location of this gateway based on incoming status messages')
.and('be.visible')
cy.findByTestId('location-map').should('be.visible')
cy.findByLabelText('Latitude').should('be.visible')
cy.findDescriptionByLabelText('Latitude')
.should('contain', 'The north-south position in degrees, where 0 is the equator')
.and('be.visible')
cy.findByLabelText('Longitude').should('be.visible')
cy.findDescriptionByLabelText('Longitude')
.should(
'contain',
'The east-west position in degrees, where 0 is the prime meridian (Greenwich)',
)
.and('be.visible')
cy.findByLabelText('Altitude').should('be.visible')
cy.findDescriptionByLabelText('Altitude')
.should('contain', 'The altitude in meters, where 0 means sea level')
.and('be.visible')

cy.findByRole('button', { name: 'Save changes' }).should('be.visible')
})

it('validates before submitting an empty form', () => {
cy.visit(`${Cypress.config('consoleRootPath')}/gateways/${gatewayId}/location`)

cy.findByRole('button', { name: 'Save changes' }).click()

cy.findErrorByLabelText('Latitude')
.should('contain.text', 'Latitude is required')
.and('be.visible')
cy.findErrorByLabelText('Longitude')
.should('contain.text', 'Longitude is required')
.and('be.visible')
cy.findErrorByLabelText('Altitude')
.should('contain.text', 'Altitude is required')
.and('be.visible')

cy.location('pathname').should(
'eq',
`${Cypress.config('consoleRootPath')}/gateways/${gatewayId}/location`,
)
})

it('disables inputs when location source is checked', () => {
cy.visit(`${Cypress.config('consoleRootPath')}/gateways/${gatewayId}/location`)
cy.findByLabelText('Location source').check()

cy.findByLabelText('Latitude').should('be.disabled')
cy.findByLabelText('Longitude').should('be.disabled')
cy.findByLabelText('Altitude').should('be.disabled')
cy.findByRole('button', { name: /Remove location entry/ }).should('be.disabled')
})

it('successfully saves location', () => {
cy.visit(`${Cypress.config('consoleRootPath')}/gateways/${gatewayId}/location`)
cy.findByLabelText('Latitude').type(coordinates.latitude)
cy.findByLabelText('Longitude').type(coordinates.longitude)
cy.findByLabelText('Altitude').type(coordinates.altitude)

cy.findByRole('button', { name: 'Save changes' }).click()

cy.findByTestId('toast-notification')
.should('be.visible')
.findByText(`Location updated`)
.should('be.visible')
cy.findByTestId('error-notification').should('not.exist')
cy.findByTestId('full-error-view').should('not.exist')
})
})
121 changes: 121 additions & 0 deletions cypress/integration/console/gateways/location/edit.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
// Copyright © 2021 The Things Network Foundation, The Things Industries B.V.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

describe('Gateway location', () => {
const gatewayId = 'test-gateway-location'
const gateway = { ids: { gateway_id: gatewayId } }
const coordinates = {
latitude: 2,
longitude: 2,
altitude: 2,
}
const userId = 'edit-gateway-location-test-user'
const user = {
ids: { user_id: userId },
primary_email_address: '[email protected]',
password: 'ABCDefg123!',
password_confirm: 'ABCDefg123!',
}

const updatedGatewayLocation = {
gateway: {
antennas: [
{
location: {
altitude: 1,
latitude: 1,
longitude: 1,
},
},
],
location_public: true,
update_location_from_status: false,
},
field_mask: {
paths: ['antennas', 'location_public', 'update_location_from_status'],
},
}

before(() => {
cy.dropAndSeedDatabase()
cy.createUser(user)
cy.loginConsole({ user_id: user.ids.user_id, password: user.password })
cy.createGateway(gateway, userId)
cy.updateGateway(gatewayId, updatedGatewayLocation)
})

beforeEach(() => {
cy.loginConsole({ user_id: user.ids.user_id, password: user.password })
})

it('successfully edits latitude, longitude, altitude', () => {
cy.visit(`${Cypress.config('consoleRootPath')}/gateways/${gatewayId}/location`)
cy.findByLabelText('Latitude').type(coordinates.latitude)
cy.findByLabelText('Longitude').type(coordinates.longitude)
cy.findByLabelText('Altitude').type(coordinates.altitude)

cy.findByRole('button', { name: 'Save changes' }).click()

cy.findByTestId('error-notification').should('not.exist')
cy.findByTestId('toast-notification')
.should('be.visible')
.findByText(`Location updated`)
.should('be.visible')
})

it('successfully edits latitude and longitude based map widget location change', () => {
cy.visit(`${Cypress.config('consoleRootPath')}/gateways/${gatewayId}/location`)
cy.findByTestId('location-map').should('be.visible')
cy.findByTestId('location-map').click(30, 30)

cy.findByLabelText('Latitude').should('not.eq', coordinates.latitude)
cy.findByLabelText('Longitude').should('not.eq', coordinates.longitude)
cy.findByLabelText('Altitude').should('not.eq', coordinates.altitude)

cy.findByRole('button', { name: 'Save changes' }).click()

cy.findByTestId('error-notification').should('not.exist')
cy.findByTestId('toast-notification')
.should('be.visible')
.findByText(`Location updated`)
.should('be.visible')
})

it('successfully deletes location entry', () => {
cy.visit(`${Cypress.config('consoleRootPath')}/gateways/${gatewayId}/location`)
cy.findByRole('button', { name: /Remove location entry/ }).click()

cy.findByTestId('modal-window')
.should('be.visible')
.within(() => {
cy.findByText('Remove location entry', { selector: 'h1' }).should('be.visible')
cy.findByRole('button', { name: /Remove location entry/ }).click()
})

cy.findByTestId('error-notification').should('not.exist')
cy.findByTestId('toast-notification')
.should('be.visible')
.findByText(`Location deleted`)
.should('be.visible')
cy.findByLabelText('Latitude')
.should('have.attr', 'value')
.and('eq', '')
cy.findByLabelText('Longitude')
.should('have.attr', 'value')
.and('eq', '')
cy.findByLabelText('Altitude')
.should('have.attr', 'value')
.and('eq', '')
})
})
1 change: 1 addition & 0 deletions cypress/integration/console/organizations/create.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ describe('Organization create', () => {
.click()

cy.findByTestId('error-notification').should('not.exist')
cy.findByTestId('full-error-view').should('not.exist')
cy.location('pathname').should(
'eq',
`${Cypress.config('consoleRootPath')}/organizations/${organizationId}`,
Expand Down
15 changes: 15 additions & 0 deletions cypress/support/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,21 @@ Cypress.Commands.add('createPubSub', (applicationId, pubSub) => {
})
})

// Helper function to update gateway programmatically.
Cypress.Commands.add('updateGateway', (gatewayId, gateway) => {
const baseUrl = Cypress.config('baseUrl')
cy.getAccessToken(accessToken => {
cy.request({
method: 'PUT',
url: `${baseUrl}/api/v3/gateways/${gatewayId}`,
body: gateway,
headers: {
Authorization: `Bearer ${accessToken}`,
},
})
})
})

// Overwrite the default `type` to make sure that subject is resolved and focused before simulating typing. This is helpful
// when:
// 1. The action is forced via the `forced` option for inputs that are visually hidden for styling purposes.
Expand Down
2 changes: 1 addition & 1 deletion pkg/webui/components/map/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ export default class LocationMap extends React.Component {
} = this.props
const { zoomLevel } = this.state
return (
<div className={classnames(style.container, className)}>
<div className={classnames(style.container, className)} data-test-id="location-map">
<Map
ref={mapRef}
className={classnames(style.map, {
Expand Down
4 changes: 2 additions & 2 deletions pkg/webui/console/components/location-form/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,12 @@ const m = defineMessages({

const validationSchema = Yup.object().shape({
latitude: Yup.number()
.test('is-valid-latitude', sharedMessages.validateLat, value =>
.test('is-valid-latitude', sharedMessages.validateLatitude, value =>
latitudeRegexp.test(String(value)),
)
.required(sharedMessages.validateRequired),
longitude: Yup.number()
.test('is-valid-longitude', sharedMessages.validateLong, value =>
.test('is-valid-longitude', sharedMessages.validateLongitude, value =>
longitudeRegexp.test(String(value)),
)
.required(sharedMessages.validateRequired),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,29 +41,34 @@ const validationSchema = Yup.object().shape({
latitude: Yup.number().when('update_location_from_status', {
is: false,
then: schema =>
schema.test('is-valid-latitude', sharedMessages.validateLat, value =>
latitudeRegexp.test(String(value)),
),
schema
.required(sharedMessages.validateRequired)
.test('is-valid-latitude', sharedMessages.validateLatitude, value =>
latitudeRegexp.test(String(value)),
),
otherwise: schema => schema.strip(),
}),
longitude: Yup.number().when('update_location_from_status', {
is: false,
then: schema =>
schema.test('is-valid-longitude', sharedMessages.validateLong, value =>
longitudeRegexp.test(String(value)),
),
schema
.required(sharedMessages.validateRequired)
.test('is-valid-longitude', sharedMessages.validateLongitude, value =>
longitudeRegexp.test(String(value)),
),
otherwise: schema => schema.strip(),
}),
altitude: Yup.number().when('update_location_from_status', {
is: false,
then: schema => schema.integer(sharedMessages.validateInt32).required(),
then: schema =>
schema.integer(sharedMessages.validateInt32).required(sharedMessages.validateRequired),
otherwise: schema => schema.strip(),
}),
location_public: Yup.bool(),
update_location_from_status: Yup.bool(),
})

const getRegistryLocation = function(antennas) {
const getRegistryLocation = antennas => {
let registryLocation
if (antennas) {
for (const key of Object.keys(antennas)) {
Expand Down

0 comments on commit fd5cd8d

Please sign in to comment.