180 changed files with 2728 additions and 1117 deletions
@ -0,0 +1,35 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2023 The Thingsboard Authors |
||||
|
* |
||||
|
* 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. |
||||
|
*/ |
||||
|
package org.thingsboard.server.common.data.sync.vc; |
||||
|
|
||||
|
import org.apache.commons.lang3.StringUtils; |
||||
|
|
||||
|
public class VcUtils { |
||||
|
|
||||
|
private VcUtils() {} |
||||
|
|
||||
|
public static void checkBranchName(String branch) { |
||||
|
if (StringUtils.isEmpty(branch)) return; |
||||
|
|
||||
|
boolean invalid = StringUtils.containsWhitespace(branch) || |
||||
|
StringUtils.containsAny(branch, "..", "~", "^", ":", "\\") || |
||||
|
StringUtils.endsWithAny(branch, "/", ".lock"); |
||||
|
if (invalid) { |
||||
|
throw new IllegalArgumentException("Branch name is invalid"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,282 @@ |
|||||
|
-- |
||||
|
-- Copyright © 2016-2023 The Thingsboard Authors |
||||
|
-- |
||||
|
-- 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. |
||||
|
-- |
||||
|
|
||||
|
DROP VIEW IF EXISTS device_info_active_attribute_view CASCADE; |
||||
|
CREATE OR REPLACE VIEW device_info_active_attribute_view AS |
||||
|
SELECT d.* |
||||
|
, c.title as customer_title |
||||
|
, COALESCE((c.additional_info::json->>'isPublic')::bool, FALSE) as customer_is_public |
||||
|
, d.type as device_profile_name |
||||
|
, COALESCE(da.bool_v, FALSE) as active |
||||
|
FROM device d |
||||
|
LEFT JOIN customer c ON c.id = d.customer_id |
||||
|
LEFT JOIN attribute_kv da ON da.entity_id = d.id and da.attribute_key = 'active'; |
||||
|
|
||||
|
DROP VIEW IF EXISTS device_info_active_ts_view CASCADE; |
||||
|
CREATE OR REPLACE VIEW device_info_active_ts_view AS |
||||
|
SELECT d.* |
||||
|
, c.title as customer_title |
||||
|
, COALESCE((c.additional_info::json->>'isPublic')::bool, FALSE) as customer_is_public |
||||
|
, d.type as device_profile_name |
||||
|
, COALESCE(dt.bool_v, FALSE) as active |
||||
|
FROM device d |
||||
|
LEFT JOIN customer c ON c.id = d.customer_id |
||||
|
LEFT JOIN ts_kv_latest dt ON dt.entity_id = d.id and dt.key = (select key_id from ts_kv_dictionary where key = 'active'); |
||||
|
|
||||
|
DROP VIEW IF EXISTS device_info_view CASCADE; |
||||
|
CREATE OR REPLACE VIEW device_info_view AS SELECT * FROM device_info_active_attribute_view; |
||||
|
|
||||
|
DROP VIEW IF EXISTS alarm_info CASCADE; |
||||
|
CREATE VIEW alarm_info AS |
||||
|
SELECT a.*, |
||||
|
(CASE WHEN a.acknowledged AND a.cleared THEN 'CLEARED_ACK' |
||||
|
WHEN NOT a.acknowledged AND a.cleared THEN 'CLEARED_UNACK' |
||||
|
WHEN a.acknowledged AND NOT a.cleared THEN 'ACTIVE_ACK' |
||||
|
WHEN NOT a.acknowledged AND NOT a.cleared THEN 'ACTIVE_UNACK' END) as status, |
||||
|
COALESCE(CASE WHEN a.originator_type = 0 THEN (select title from tenant where id = a.originator_id) |
||||
|
WHEN a.originator_type = 1 THEN (select title from customer where id = a.originator_id) |
||||
|
WHEN a.originator_type = 2 THEN (select email from tb_user where id = a.originator_id) |
||||
|
WHEN a.originator_type = 3 THEN (select title from dashboard where id = a.originator_id) |
||||
|
WHEN a.originator_type = 4 THEN (select name from asset where id = a.originator_id) |
||||
|
WHEN a.originator_type = 5 THEN (select name from device where id = a.originator_id) |
||||
|
WHEN a.originator_type = 9 THEN (select name from entity_view where id = a.originator_id) |
||||
|
WHEN a.originator_type = 13 THEN (select name from device_profile where id = a.originator_id) |
||||
|
WHEN a.originator_type = 14 THEN (select name from asset_profile where id = a.originator_id) |
||||
|
WHEN a.originator_type = 18 THEN (select name from edge where id = a.originator_id) END |
||||
|
, 'Deleted') originator_name, |
||||
|
COALESCE(CASE WHEN a.originator_type = 0 THEN (select title from tenant where id = a.originator_id) |
||||
|
WHEN a.originator_type = 1 THEN (select COALESCE(NULLIF(title, ''), email) from customer where id = a.originator_id) |
||||
|
WHEN a.originator_type = 2 THEN (select email from tb_user where id = a.originator_id) |
||||
|
WHEN a.originator_type = 3 THEN (select title from dashboard where id = a.originator_id) |
||||
|
WHEN a.originator_type = 4 THEN (select COALESCE(NULLIF(label, ''), name) from asset where id = a.originator_id) |
||||
|
WHEN a.originator_type = 5 THEN (select COALESCE(NULLIF(label, ''), name) from device where id = a.originator_id) |
||||
|
WHEN a.originator_type = 9 THEN (select name from entity_view where id = a.originator_id) |
||||
|
WHEN a.originator_type = 13 THEN (select name from device_profile where id = a.originator_id) |
||||
|
WHEN a.originator_type = 14 THEN (select name from asset_profile where id = a.originator_id) |
||||
|
WHEN a.originator_type = 18 THEN (select COALESCE(NULLIF(label, ''), name) from edge where id = a.originator_id) END |
||||
|
, 'Deleted') as originator_label, |
||||
|
u.first_name as assignee_first_name, u.last_name as assignee_last_name, u.email as assignee_email |
||||
|
FROM alarm a |
||||
|
LEFT JOIN tb_user u ON u.id = a.assignee_id; |
||||
|
|
||||
|
CREATE OR REPLACE FUNCTION create_or_update_active_alarm( |
||||
|
t_id uuid, c_id uuid, a_id uuid, a_created_ts bigint, |
||||
|
a_o_id uuid, a_o_type integer, a_type varchar, |
||||
|
a_severity varchar, a_start_ts bigint, a_end_ts bigint, |
||||
|
a_details varchar, |
||||
|
a_propagate boolean, a_propagate_to_owner boolean, |
||||
|
a_propagate_to_tenant boolean, a_propagation_types varchar, |
||||
|
a_creation_enabled boolean) |
||||
|
RETURNS varchar |
||||
|
LANGUAGE plpgsql |
||||
|
AS |
||||
|
$$ |
||||
|
DECLARE |
||||
|
null_id constant uuid = '13814000-1dd2-11b2-8080-808080808080'::uuid; |
||||
|
existing alarm; |
||||
|
result alarm_info; |
||||
|
row_count integer; |
||||
|
BEGIN |
||||
|
SELECT * INTO existing FROM alarm a WHERE a.originator_id = a_o_id AND a.type = a_type AND a.cleared = false ORDER BY a.start_ts DESC FOR UPDATE; |
||||
|
IF existing.id IS NULL THEN |
||||
|
IF a_creation_enabled = FALSE THEN |
||||
|
RETURN json_build_object('success', false)::text; |
||||
|
END IF; |
||||
|
IF c_id = null_id THEN |
||||
|
c_id = NULL; |
||||
|
end if; |
||||
|
INSERT INTO alarm |
||||
|
(tenant_id, customer_id, id, created_time, |
||||
|
originator_id, originator_type, type, |
||||
|
severity, start_ts, end_ts, |
||||
|
additional_info, |
||||
|
propagate, propagate_to_owner, propagate_to_tenant, propagate_relation_types, |
||||
|
acknowledged, ack_ts, |
||||
|
cleared, clear_ts, |
||||
|
assignee_id, assign_ts) |
||||
|
VALUES |
||||
|
(t_id, c_id, a_id, a_created_ts, |
||||
|
a_o_id, a_o_type, a_type, |
||||
|
a_severity, a_start_ts, a_end_ts, |
||||
|
a_details, |
||||
|
a_propagate, a_propagate_to_owner, a_propagate_to_tenant, a_propagation_types, |
||||
|
false, 0, false, 0, NULL, 0); |
||||
|
SELECT * INTO result FROM alarm_info a WHERE a.id = a_id AND a.tenant_id = t_id; |
||||
|
RETURN json_build_object('success', true, 'created', true, 'modified', true, 'alarm', row_to_json(result))::text; |
||||
|
ELSE |
||||
|
UPDATE alarm a |
||||
|
SET severity = a_severity, |
||||
|
start_ts = a_start_ts, |
||||
|
end_ts = a_end_ts, |
||||
|
additional_info = a_details, |
||||
|
propagate = a_propagate, |
||||
|
propagate_to_owner = a_propagate_to_owner, |
||||
|
propagate_to_tenant = a_propagate_to_tenant, |
||||
|
propagate_relation_types = a_propagation_types |
||||
|
WHERE a.id = existing.id |
||||
|
AND a.tenant_id = t_id |
||||
|
AND (severity != a_severity OR start_ts != a_start_ts OR end_ts != a_end_ts OR additional_info != a_details |
||||
|
OR propagate != a_propagate OR propagate_to_owner != a_propagate_to_owner OR |
||||
|
propagate_to_tenant != a_propagate_to_tenant OR propagate_relation_types != a_propagation_types); |
||||
|
GET DIAGNOSTICS row_count = ROW_COUNT; |
||||
|
SELECT * INTO result FROM alarm_info a WHERE a.id = existing.id AND a.tenant_id = t_id; |
||||
|
IF row_count > 0 THEN |
||||
|
RETURN json_build_object('success', true, 'modified', true, 'alarm', row_to_json(result), 'old', row_to_json(existing))::text; |
||||
|
ELSE |
||||
|
RETURN json_build_object('success', true, 'modified', false, 'alarm', row_to_json(result))::text; |
||||
|
END IF; |
||||
|
END IF; |
||||
|
END |
||||
|
$$; |
||||
|
|
||||
|
DROP FUNCTION IF EXISTS update_alarm; |
||||
|
CREATE OR REPLACE FUNCTION update_alarm(t_id uuid, a_id uuid, a_severity varchar, a_start_ts bigint, a_end_ts bigint, |
||||
|
a_details varchar, |
||||
|
a_propagate boolean, a_propagate_to_owner boolean, |
||||
|
a_propagate_to_tenant boolean, a_propagation_types varchar) |
||||
|
RETURNS varchar |
||||
|
LANGUAGE plpgsql |
||||
|
AS |
||||
|
$$ |
||||
|
DECLARE |
||||
|
existing alarm; |
||||
|
result alarm_info; |
||||
|
row_count integer; |
||||
|
BEGIN |
||||
|
SELECT * INTO existing FROM alarm a WHERE a.id = a_id AND a.tenant_id = t_id FOR UPDATE; |
||||
|
IF existing IS NULL THEN |
||||
|
RETURN json_build_object('success', false)::text; |
||||
|
END IF; |
||||
|
UPDATE alarm a |
||||
|
SET severity = a_severity, |
||||
|
start_ts = a_start_ts, |
||||
|
end_ts = a_end_ts, |
||||
|
additional_info = a_details, |
||||
|
propagate = a_propagate, |
||||
|
propagate_to_owner = a_propagate_to_owner, |
||||
|
propagate_to_tenant = a_propagate_to_tenant, |
||||
|
propagate_relation_types = a_propagation_types |
||||
|
WHERE a.id = a_id |
||||
|
AND a.tenant_id = t_id |
||||
|
AND (severity != a_severity OR start_ts != a_start_ts OR end_ts != a_end_ts OR additional_info != a_details |
||||
|
OR propagate != a_propagate OR propagate_to_owner != a_propagate_to_owner OR |
||||
|
propagate_to_tenant != a_propagate_to_tenant OR propagate_relation_types != a_propagation_types); |
||||
|
GET DIAGNOSTICS row_count = ROW_COUNT; |
||||
|
SELECT * INTO result FROM alarm_info a WHERE a.id = a_id AND a.tenant_id = t_id; |
||||
|
IF row_count > 0 THEN |
||||
|
RETURN json_build_object('success', true, 'modified', row_count > 0, 'alarm', row_to_json(result), 'old', row_to_json(existing))::text; |
||||
|
ELSE |
||||
|
RETURN json_build_object('success', true, 'modified', row_count > 0, 'alarm', row_to_json(result))::text; |
||||
|
END IF; |
||||
|
END |
||||
|
$$; |
||||
|
|
||||
|
DROP FUNCTION IF EXISTS acknowledge_alarm; |
||||
|
CREATE OR REPLACE FUNCTION acknowledge_alarm(t_id uuid, a_id uuid, a_ts bigint) |
||||
|
RETURNS varchar |
||||
|
LANGUAGE plpgsql |
||||
|
AS |
||||
|
$$ |
||||
|
DECLARE |
||||
|
existing alarm; |
||||
|
result alarm_info; |
||||
|
modified boolean = FALSE; |
||||
|
BEGIN |
||||
|
SELECT * INTO existing FROM alarm a WHERE a.id = a_id AND a.tenant_id = t_id FOR UPDATE; |
||||
|
IF existing IS NULL THEN |
||||
|
RETURN json_build_object('success', false)::text; |
||||
|
END IF; |
||||
|
|
||||
|
IF NOT (existing.acknowledged) THEN |
||||
|
modified = TRUE; |
||||
|
UPDATE alarm a SET acknowledged = true, ack_ts = a_ts WHERE a.id = a_id AND a.tenant_id = t_id; |
||||
|
END IF; |
||||
|
SELECT * INTO result FROM alarm_info a WHERE a.id = a_id AND a.tenant_id = t_id; |
||||
|
RETURN json_build_object('success', true, 'modified', modified, 'alarm', row_to_json(result), 'old', row_to_json(existing))::text; |
||||
|
END |
||||
|
$$; |
||||
|
|
||||
|
DROP FUNCTION IF EXISTS clear_alarm; |
||||
|
CREATE OR REPLACE FUNCTION clear_alarm(t_id uuid, a_id uuid, a_ts bigint, a_details varchar) |
||||
|
RETURNS varchar |
||||
|
LANGUAGE plpgsql |
||||
|
AS |
||||
|
$$ |
||||
|
DECLARE |
||||
|
existing alarm; |
||||
|
result alarm_info; |
||||
|
cleared boolean = FALSE; |
||||
|
BEGIN |
||||
|
SELECT * INTO existing FROM alarm a WHERE a.id = a_id AND a.tenant_id = t_id FOR UPDATE; |
||||
|
IF existing IS NULL THEN |
||||
|
RETURN json_build_object('success', false)::text; |
||||
|
END IF; |
||||
|
IF NOT(existing.cleared) THEN |
||||
|
cleared = TRUE; |
||||
|
UPDATE alarm a SET cleared = true, clear_ts = a_ts, additional_info = a_details WHERE a.id = a_id AND a.tenant_id = t_id; |
||||
|
END IF; |
||||
|
SELECT * INTO result FROM alarm_info a WHERE a.id = a_id AND a.tenant_id = t_id; |
||||
|
RETURN json_build_object('success', true, 'cleared', cleared, 'alarm', row_to_json(result))::text; |
||||
|
END |
||||
|
$$; |
||||
|
|
||||
|
DROP FUNCTION IF EXISTS assign_alarm; |
||||
|
CREATE OR REPLACE FUNCTION assign_alarm(t_id uuid, a_id uuid, u_id uuid, a_ts bigint) |
||||
|
RETURNS varchar |
||||
|
LANGUAGE plpgsql |
||||
|
AS |
||||
|
$$ |
||||
|
DECLARE |
||||
|
existing alarm; |
||||
|
result alarm_info; |
||||
|
modified boolean = FALSE; |
||||
|
BEGIN |
||||
|
SELECT * INTO existing FROM alarm a WHERE a.id = a_id AND a.tenant_id = t_id FOR UPDATE; |
||||
|
IF existing IS NULL THEN |
||||
|
RETURN json_build_object('success', false)::text; |
||||
|
END IF; |
||||
|
IF existing.assignee_id IS NULL OR existing.assignee_id != u_id THEN |
||||
|
modified = TRUE; |
||||
|
UPDATE alarm a SET assignee_id = u_id, assign_ts = a_ts WHERE a.id = a_id AND a.tenant_id = t_id; |
||||
|
END IF; |
||||
|
SELECT * INTO result FROM alarm_info a WHERE a.id = a_id AND a.tenant_id = t_id; |
||||
|
RETURN json_build_object('success', true, 'modified', modified, 'alarm', row_to_json(result))::text; |
||||
|
END |
||||
|
$$; |
||||
|
|
||||
|
DROP FUNCTION IF EXISTS unassign_alarm; |
||||
|
CREATE OR REPLACE FUNCTION unassign_alarm(t_id uuid, a_id uuid, a_ts bigint) |
||||
|
RETURNS varchar |
||||
|
LANGUAGE plpgsql |
||||
|
AS |
||||
|
$$ |
||||
|
DECLARE |
||||
|
existing alarm; |
||||
|
result alarm_info; |
||||
|
modified boolean = FALSE; |
||||
|
BEGIN |
||||
|
SELECT * INTO existing FROM alarm a WHERE a.id = a_id AND a.tenant_id = t_id FOR UPDATE; |
||||
|
IF existing IS NULL THEN |
||||
|
RETURN json_build_object('success', false)::text; |
||||
|
END IF; |
||||
|
IF existing.assignee_id IS NOT NULL THEN |
||||
|
modified = TRUE; |
||||
|
UPDATE alarm a SET assignee_id = NULL, assign_ts = a_ts WHERE a.id = a_id AND a.tenant_id = t_id; |
||||
|
END IF; |
||||
|
SELECT * INTO result FROM alarm_info a WHERE a.id = a_id AND a.tenant_id = t_id; |
||||
|
RETURN json_build_object('success', true, 'modified', modified, 'alarm', row_to_json(result))::text; |
||||
|
END |
||||
|
$$; |
||||
@ -0,0 +1,39 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2023 The Thingsboard Authors |
||||
|
* |
||||
|
* 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. |
||||
|
*/ |
||||
|
package org.thingsboard.server.msa.ui.pages; |
||||
|
|
||||
|
import org.openqa.selenium.WebDriver; |
||||
|
import org.openqa.selenium.WebElement; |
||||
|
|
||||
|
public class AlarmWidgetElements extends AlarmDetailsEntityTabHelper { |
||||
|
public AlarmWidgetElements(WebDriver driver) { |
||||
|
super(driver); |
||||
|
} |
||||
|
|
||||
|
private static final String ASSIGN_USER_DISPLAY_NAME = "//span[contains(@class,'assigned-container')]/span[contains(text(),'%s')]"; |
||||
|
private static final String UNASSIGNED = "//span[text() = '%s']/ancestor::mat-row//span[contains(@class,'assigned-container')]" + |
||||
|
"//mat-icon[text() = 'account_circle']/following-sibling::span"; |
||||
|
|
||||
|
@Override |
||||
|
public WebElement assignedUser(String userEmail) { |
||||
|
return waitUntilElementToBeClickable(String.format(ASSIGN_USER_DISPLAY_NAME, userEmail)); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public WebElement unassigned(String alarmType) { |
||||
|
return waitUntilVisibilityOfElementLocated(String.format(UNASSIGNED, alarmType)); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,72 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2023 The Thingsboard Authors |
||||
|
* |
||||
|
* 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. |
||||
|
*/ |
||||
|
package org.thingsboard.server.msa.ui.pages; |
||||
|
|
||||
|
import org.openqa.selenium.WebDriver; |
||||
|
import org.openqa.selenium.WebElement; |
||||
|
import org.thingsboard.server.msa.ui.base.AbstractBasePage; |
||||
|
|
||||
|
public class CreateWidgetPopupElements extends AbstractBasePage { |
||||
|
public CreateWidgetPopupElements(WebDriver driver) { |
||||
|
super(driver); |
||||
|
} |
||||
|
|
||||
|
private static final String ENTITY_ALIAS = "//input[@formcontrolname='entityAlias']"; |
||||
|
private static final String CREATE_NEW_ALIAS_BTN = "//a[text() = 'Create a new one!']/parent::span"; |
||||
|
private static final String FILTER_TYPE_FIELD = "//div[contains(@class,'tb-entity-filter')]//mat-select//span"; |
||||
|
private static final String TYPE_FIELD = "//mat-select[@formcontrolname='entityType']//span"; |
||||
|
private static final String OPTION_FROM_DROPDOWN = "//span[text() = ' %s ']"; |
||||
|
private static final String ENTITY_FIELD = "//input[@formcontrolname='entity']"; |
||||
|
private static final String ADD_ALIAS_BTN = "//tb-entity-alias-dialog//span[text() = ' Add ']/parent::button"; |
||||
|
private static final String ADD_WIDGET_BTN = "//tb-add-widget-dialog//span[text() = ' Add ']/parent::button"; |
||||
|
private static final String ENTITY_FROM_DROPDOWN = "//b[text() = '%s']"; |
||||
|
|
||||
|
public WebElement entityAlias() { |
||||
|
return waitUntilElementToBeClickable(ENTITY_ALIAS); |
||||
|
} |
||||
|
|
||||
|
public WebElement createNewAliasBtn() { |
||||
|
return waitUntilElementToBeClickable(CREATE_NEW_ALIAS_BTN); |
||||
|
} |
||||
|
|
||||
|
public WebElement filterTypeFiled() { |
||||
|
return waitUntilElementToBeClickable(FILTER_TYPE_FIELD); |
||||
|
} |
||||
|
|
||||
|
public WebElement typeFiled() { |
||||
|
return waitUntilElementToBeClickable(TYPE_FIELD); |
||||
|
} |
||||
|
|
||||
|
public WebElement optionFromDropdown(String type) { |
||||
|
return waitUntilElementToBeClickable(String.format(OPTION_FROM_DROPDOWN, type)); |
||||
|
} |
||||
|
|
||||
|
public WebElement entityFiled() { |
||||
|
return waitUntilElementToBeClickable(ENTITY_FIELD); |
||||
|
} |
||||
|
|
||||
|
public WebElement addAliasBtn() { |
||||
|
return waitUntilElementToBeClickable(ADD_ALIAS_BTN); |
||||
|
} |
||||
|
|
||||
|
public WebElement addWidgetBtn() { |
||||
|
return waitUntilElementToBeClickable(ADD_WIDGET_BTN); |
||||
|
} |
||||
|
|
||||
|
public WebElement entityFromDropdown(String entityName) { |
||||
|
return waitUntilVisibilityOfElementLocated(String.format(ENTITY_FROM_DROPDOWN, entityName)); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,48 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2023 The Thingsboard Authors |
||||
|
* |
||||
|
* 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. |
||||
|
*/ |
||||
|
package org.thingsboard.server.msa.ui.pages; |
||||
|
|
||||
|
import org.openqa.selenium.Keys; |
||||
|
import org.openqa.selenium.WebDriver; |
||||
|
import org.testcontainers.shaded.org.apache.commons.lang3.RandomStringUtils; |
||||
|
|
||||
|
public class CreateWidgetPopupHelper extends CreateWidgetPopupElements { |
||||
|
public CreateWidgetPopupHelper(WebDriver driver) { |
||||
|
super(driver); |
||||
|
} |
||||
|
|
||||
|
public void goToCreateEntityAliasPopup(String aliasName) { |
||||
|
entityAlias().sendKeys(aliasName + RandomStringUtils.randomAlphanumeric(7)); |
||||
|
createNewAliasBtn().click(); |
||||
|
} |
||||
|
|
||||
|
public void selectFilterType(String filterType) { |
||||
|
filterTypeFiled().click(); |
||||
|
optionFromDropdown(filterType).click(); |
||||
|
} |
||||
|
|
||||
|
public void selectType(String entityType) { |
||||
|
typeFiled().click(); |
||||
|
optionFromDropdown(entityType).click(); |
||||
|
} |
||||
|
|
||||
|
public void selectEntity(String entityName) { |
||||
|
entityFiled().sendKeys(entityName); |
||||
|
entityFromDropdown(entityName); |
||||
|
entityFiled().sendKeys(Keys.ARROW_DOWN); |
||||
|
entityFiled().sendKeys(Keys.ENTER); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,146 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2023 The Thingsboard Authors |
||||
|
* |
||||
|
* 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. |
||||
|
*/ |
||||
|
package org.thingsboard.server.msa.ui.tests.assignee; |
||||
|
|
||||
|
import io.qameta.allure.Description; |
||||
|
import io.qameta.allure.Feature; |
||||
|
import org.testng.annotations.AfterClass; |
||||
|
import org.testng.annotations.BeforeClass; |
||||
|
import org.testng.annotations.BeforeMethod; |
||||
|
import org.testng.annotations.Test; |
||||
|
import org.thingsboard.server.common.data.Dashboard; |
||||
|
import org.thingsboard.server.msa.ui.pages.AlarmWidgetElements; |
||||
|
import org.thingsboard.server.msa.ui.pages.CreateWidgetPopupHelper; |
||||
|
import org.thingsboard.server.msa.ui.pages.DashboardPageHelper; |
||||
|
import org.thingsboard.server.msa.ui.utils.Const; |
||||
|
import org.thingsboard.server.msa.ui.utils.EntityPrototypes; |
||||
|
|
||||
|
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
|
||||
|
@Feature("Assign from details tab of entity") |
||||
|
public class AssignFromAlarmWidgetTest extends AbstractAssignTest { |
||||
|
|
||||
|
private Dashboard dashboard; |
||||
|
private DashboardPageHelper dashboardPage; |
||||
|
private AlarmWidgetElements alarmWidget; |
||||
|
|
||||
|
@BeforeClass |
||||
|
public void create() { |
||||
|
dashboardPage = new DashboardPageHelper(driver); |
||||
|
CreateWidgetPopupHelper createWidgetPopup = new CreateWidgetPopupHelper(driver); |
||||
|
alarmWidget = new AlarmWidgetElements(driver); |
||||
|
|
||||
|
dashboard = testRestClient.postDashboard(EntityPrototypes.defaultDashboardPrototype("Dashboard")); |
||||
|
sideBarMenuView.dashboardBtn().click(); |
||||
|
dashboardPage.entity(dashboard.getName()).click(); |
||||
|
dashboardPage.editBtn().click(); |
||||
|
dashboardPage.openSelectWidgetsBundleMenu(); |
||||
|
dashboardPage.openCreateWidgetPopup(); |
||||
|
createWidgetPopup.goToCreateEntityAliasPopup("Alias"); |
||||
|
createWidgetPopup.selectFilterType("Single entity"); |
||||
|
createWidgetPopup.selectType("Device"); |
||||
|
createWidgetPopup.selectEntity(deviceName); |
||||
|
createWidgetPopup.addAliasBtn().click(); |
||||
|
createWidgetPopup.addWidgetBtn().click(); |
||||
|
dashboardPage.increaseSizeOfTheWidget(); |
||||
|
dashboardPage.doneBtn().click(); |
||||
|
} |
||||
|
|
||||
|
@AfterClass |
||||
|
public void delete() { |
||||
|
deleteDashboardById(dashboard.getId()); |
||||
|
} |
||||
|
|
||||
|
@BeforeMethod |
||||
|
public void goToDashboardPage() { |
||||
|
sideBarMenuView.dashboardBtn().click(); |
||||
|
dashboardPage.entity(dashboard.getName()).click(); |
||||
|
} |
||||
|
|
||||
|
@Description("Can assign alarm to yourself") |
||||
|
@Test |
||||
|
public void assignAlarmToYourself() { |
||||
|
alarmWidget.assignAlarmTo(alarmType, Const.TENANT_EMAIL); |
||||
|
|
||||
|
assertIsDisplayed(alarmWidget.assignedUser(Const.TENANT_EMAIL)); |
||||
|
} |
||||
|
|
||||
|
@Description("Can reassign alarm to another user") |
||||
|
@Test |
||||
|
public void reassignAlarm() { |
||||
|
alarmWidget.assignAlarmTo(assignedAlarmType, userWithNameEmail); |
||||
|
|
||||
|
assertIsDisplayed(alarmWidget.assignedUser(userName)); |
||||
|
} |
||||
|
|
||||
|
@Description("Can unassign alarm") |
||||
|
@Test |
||||
|
public void unassignedAlarm() { |
||||
|
alarmWidget.unassignedAlarm(assignedAlarmType); |
||||
|
|
||||
|
assertIsDisplayed(alarmWidget.unassigned(assignedAlarmType)); |
||||
|
} |
||||
|
|
||||
|
@Description("Assign alarm to yourself from details of alarm") |
||||
|
@Test |
||||
|
public void assignAlarmToYourselfFromDetails() { |
||||
|
alarmWidget.alarmDetailsBtn(alarmType).click(); |
||||
|
alarmDetailsView.assignAlarmTo(Const.TENANT_EMAIL); |
||||
|
alarmDetailsView.closeAlarmDetailsViewBtn().click(); |
||||
|
|
||||
|
assertIsDisplayed(alarmWidget.assignedUser(Const.TENANT_EMAIL)); |
||||
|
} |
||||
|
|
||||
|
@Description("Reassign alarm to another user from details of alarm") |
||||
|
@Test |
||||
|
public void reassignAlarmFromDetails() { |
||||
|
alarmWidget.alarmDetailsBtn(assignedAlarmType).click(); |
||||
|
alarmDetailsView.assignAlarmTo(userWithNameEmail); |
||||
|
alarmDetailsView.closeAlarmDetailsViewBtn().click(); |
||||
|
|
||||
|
assertIsDisplayed(alarmWidget.assignedUser(userName)); |
||||
|
} |
||||
|
|
||||
|
@Description("Unassign alarm from details of alarm") |
||||
|
@Test |
||||
|
public void unassignedAlarmFromDetails() { |
||||
|
alarmWidget.alarmDetailsBtn(assignedAlarmType).click(); |
||||
|
alarmDetailsView.unassignedAlarm(); |
||||
|
alarmDetailsView.closeAlarmDetailsViewBtn().click(); |
||||
|
|
||||
|
assertIsDisplayed(alarmWidget.unassigned(assignedAlarmType)); |
||||
|
} |
||||
|
|
||||
|
@Description("Search by email") |
||||
|
@Test |
||||
|
public void searchByEmail() { |
||||
|
alarmWidget.searchAlarm(alarmType, Const.TENANT_EMAIL); |
||||
|
alarmWidget.setUsers(); |
||||
|
|
||||
|
assertThat(alarmWidget.getUsers()).hasSize(1).as("Search result contains search input").contains(Const.TENANT_EMAIL); |
||||
|
alarmWidget.assignUsers().forEach(this::assertIsDisplayed); |
||||
|
} |
||||
|
|
||||
|
@Description("Search by name") |
||||
|
@Test(groups = "broken") |
||||
|
public void searchByName() { |
||||
|
alarmWidget.searchAlarm(alarmType, userName); |
||||
|
alarmWidget.setUsers(); |
||||
|
|
||||
|
assertThat(alarmWidget.getUsers()).hasSize(1).as("Search result contains search input").contains(userName); |
||||
|
alarmWidget.assignUsers().forEach(this::assertIsDisplayed); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,45 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2023 The Thingsboard Authors |
||||
|
* |
||||
|
* 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. |
||||
|
*/ |
||||
|
package org.thingsboard.server.msa.ui.tests.devicessmoke; |
||||
|
|
||||
|
import io.qameta.allure.Epic; |
||||
|
import org.testng.annotations.AfterMethod; |
||||
|
import org.testng.annotations.BeforeClass; |
||||
|
import org.thingsboard.server.msa.ui.base.AbstractDriverBaseTest; |
||||
|
import org.thingsboard.server.msa.ui.pages.DevicePageHelper; |
||||
|
import org.thingsboard.server.msa.ui.pages.LoginPageHelper; |
||||
|
import org.thingsboard.server.msa.ui.pages.SideBarMenuViewHelper; |
||||
|
|
||||
|
@Epic("Device smoke tests") |
||||
|
abstract public class AbstractDeviceTest extends AbstractDriverBaseTest { |
||||
|
|
||||
|
protected SideBarMenuViewHelper sideBarMenuView; |
||||
|
protected DevicePageHelper devicePage; |
||||
|
protected String deviceName; |
||||
|
|
||||
|
@BeforeClass |
||||
|
public void login() { |
||||
|
new LoginPageHelper(driver).authorizationTenant(); |
||||
|
sideBarMenuView = new SideBarMenuViewHelper(driver); |
||||
|
devicePage = new DevicePageHelper(driver); |
||||
|
} |
||||
|
|
||||
|
@AfterMethod |
||||
|
public void delete() { |
||||
|
deleteDeviceByName(deviceName); |
||||
|
deviceName = null; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,214 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2023 The Thingsboard Authors |
||||
|
* |
||||
|
* 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. |
||||
|
*/ |
||||
|
package org.thingsboard.server.msa.ui.tests.devicessmoke; |
||||
|
|
||||
|
import io.qameta.allure.Description; |
||||
|
import io.qameta.allure.Feature; |
||||
|
import org.testng.annotations.Test; |
||||
|
import org.thingsboard.server.common.data.Device; |
||||
|
import org.thingsboard.server.msa.ui.utils.EntityPrototypes; |
||||
|
|
||||
|
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
import static org.thingsboard.server.msa.ui.base.AbstractBasePage.random; |
||||
|
import static org.thingsboard.server.msa.ui.utils.Const.DEVICE_PROFILE_IS_REQUIRED_MESSAGE; |
||||
|
import static org.thingsboard.server.msa.ui.utils.Const.EMPTY_DEVICE_MESSAGE; |
||||
|
import static org.thingsboard.server.msa.ui.utils.Const.ENTITY_NAME; |
||||
|
import static org.thingsboard.server.msa.ui.utils.Const.NAME_IS_REQUIRED_MESSAGE; |
||||
|
import static org.thingsboard.server.msa.ui.utils.Const.SAME_NAME_WARNING_DEVICE_MESSAGE; |
||||
|
|
||||
|
@Feature("Create device") |
||||
|
public class CreateDeviceTest extends AbstractDeviceTest { |
||||
|
|
||||
|
@Test(groups = "smoke") |
||||
|
@Description("Add device after specifying the name (text/numbers /special characters)") |
||||
|
public void createDevice() { |
||||
|
deviceName = ENTITY_NAME + random(); |
||||
|
|
||||
|
sideBarMenuView.goToDevicesPage(); |
||||
|
devicePage.openCreateDeviceView(); |
||||
|
devicePage.enterName(deviceName); |
||||
|
devicePage.addBtnC().click(); |
||||
|
devicePage.refreshBtn().click(); |
||||
|
|
||||
|
assertIsDisplayed(devicePage.entity(deviceName)); |
||||
|
} |
||||
|
|
||||
|
@Test(groups = "smoke") |
||||
|
@Description("Add device after specifying the name and description (text/numbers /special characters)") |
||||
|
public void createDeviceWithDescription() { |
||||
|
deviceName = ENTITY_NAME + random(); |
||||
|
|
||||
|
sideBarMenuView.goToDevicesPage(); |
||||
|
devicePage.openCreateDeviceView(); |
||||
|
devicePage.enterName(deviceName); |
||||
|
devicePage.enterDescription(deviceName); |
||||
|
devicePage.addBtnC().click(); |
||||
|
devicePage.refreshBtn().click(); |
||||
|
devicePage.entity(deviceName).click(); |
||||
|
devicePage.setHeaderName(); |
||||
|
|
||||
|
assertThat(devicePage.getHeaderName()).as("Header of device details tab").isEqualTo(deviceName); |
||||
|
assertThat(devicePage.descriptionEntityView().getAttribute("value")) |
||||
|
.as("Description in device details tab").isEqualTo(deviceName); |
||||
|
} |
||||
|
|
||||
|
@Test(groups = "smoke") |
||||
|
@Description("Add device without the name") |
||||
|
public void createDeviceWithoutName() { |
||||
|
sideBarMenuView.goToDevicesPage(); |
||||
|
devicePage.openCreateDeviceView(); |
||||
|
devicePage.nameField().click(); |
||||
|
devicePage.addBtnC().click(); |
||||
|
|
||||
|
assertIsDisplayed(devicePage.addDeviceView()); |
||||
|
assertThat(devicePage.errorMessage().getText()).as("Text of warning message").isEqualTo(NAME_IS_REQUIRED_MESSAGE); |
||||
|
} |
||||
|
|
||||
|
@Test(groups = "smoke") |
||||
|
@Description("Create device only with spase in name") |
||||
|
public void createDeviceWithOnlySpace() { |
||||
|
sideBarMenuView.goToDevicesPage(); |
||||
|
devicePage.openCreateDeviceView(); |
||||
|
devicePage.enterName(" "); |
||||
|
devicePage.addBtnC().click(); |
||||
|
|
||||
|
assertIsDisplayed(devicePage.warningMessage()); |
||||
|
assertThat(devicePage.warningMessage().getText()).as("Text of warning message").isEqualTo(EMPTY_DEVICE_MESSAGE); |
||||
|
assertIsDisplayed(devicePage.addDeviceView()); |
||||
|
} |
||||
|
|
||||
|
@Test(groups = "smoke") |
||||
|
@Description("Create a device with the same name") |
||||
|
public void createDeviceWithSameName() { |
||||
|
Device device = testRestClient.postDevice("", EntityPrototypes.defaultDevicePrototype(ENTITY_NAME)); |
||||
|
deviceName = device.getName(); |
||||
|
|
||||
|
sideBarMenuView.goToDevicesPage(); |
||||
|
devicePage.openCreateDeviceView(); |
||||
|
devicePage.enterName(deviceName); |
||||
|
devicePage.addBtnC().click(); |
||||
|
|
||||
|
assertIsDisplayed(devicePage.warningMessage()); |
||||
|
assertThat(devicePage.warningMessage().getText()).as("Text of warning message").isEqualTo(SAME_NAME_WARNING_DEVICE_MESSAGE); |
||||
|
assertIsDisplayed(devicePage.addDeviceView()); |
||||
|
} |
||||
|
|
||||
|
@Test(groups = "smoke") |
||||
|
@Description("Add device after specifying the name (text/numbers /special characters) without refresh") |
||||
|
public void createDeviceWithoutRefresh() { |
||||
|
deviceName = ENTITY_NAME + random(); |
||||
|
|
||||
|
sideBarMenuView.goToDevicesPage(); |
||||
|
devicePage.openCreateDeviceView(); |
||||
|
devicePage.enterName(deviceName); |
||||
|
devicePage.addBtnC().click(); |
||||
|
|
||||
|
assertIsDisplayed(devicePage.entity(deviceName)); |
||||
|
} |
||||
|
|
||||
|
@Test(groups = "smoke") |
||||
|
@Description("Add device without device profile") |
||||
|
public void createDeviceWithoutDeviceProfile() { |
||||
|
deviceName = ENTITY_NAME + random(); |
||||
|
|
||||
|
sideBarMenuView.goToDevicesPage(); |
||||
|
devicePage.openCreateDeviceView(); |
||||
|
devicePage.enterName(deviceName); |
||||
|
devicePage.clearProfileFieldBtn().click(); |
||||
|
devicePage.addBtnC().click(); |
||||
|
|
||||
|
assertIsDisplayed(devicePage.errorMessage()); |
||||
|
assertThat(devicePage.errorMessage().getText()).as("Text of warning message").isEqualTo(DEVICE_PROFILE_IS_REQUIRED_MESSAGE); |
||||
|
assertIsDisplayed(devicePage.addDeviceView()); |
||||
|
} |
||||
|
|
||||
|
@Test(groups = "smoke") |
||||
|
@Description("Add device with enabled gateway") |
||||
|
public void createDeviceWithEnableGateway() { |
||||
|
deviceName = ENTITY_NAME + random(); |
||||
|
|
||||
|
sideBarMenuView.goToDevicesPage(); |
||||
|
devicePage.openCreateDeviceView(); |
||||
|
devicePage.enterName(deviceName); |
||||
|
devicePage.checkboxGatewayCreate().click(); |
||||
|
devicePage.addBtnC().click(); |
||||
|
|
||||
|
assertIsDisplayed(devicePage.device(deviceName)); |
||||
|
assertIsDisplayed(devicePage.checkboxGatewayPage(deviceName)); |
||||
|
} |
||||
|
|
||||
|
@Test(groups = "smoke") |
||||
|
@Description("Add device with enabled overwrite activity time for connected") |
||||
|
public void createDeviceWithEnableOverwriteActivityTimeForConnected() { |
||||
|
deviceName = ENTITY_NAME + random(); |
||||
|
|
||||
|
sideBarMenuView.goToDevicesPage(); |
||||
|
devicePage.openCreateDeviceView(); |
||||
|
devicePage.enterName(deviceName); |
||||
|
devicePage.checkboxGatewayCreate().click(); |
||||
|
devicePage.checkboxOverwriteActivityTimeCreate().click(); |
||||
|
devicePage.addBtnC().click(); |
||||
|
devicePage.device(deviceName).click(); |
||||
|
|
||||
|
assertThat(devicePage.checkboxOverwriteActivityTimeDetails().getAttribute("class").contains("selected")) |
||||
|
.as("Overwrite activity time for connected is enable").isTrue(); |
||||
|
} |
||||
|
|
||||
|
@Test(groups = "smoke") |
||||
|
@Description("Add device with label") |
||||
|
public void createDeviceWithLabel() { |
||||
|
deviceName = ENTITY_NAME + random(); |
||||
|
String deviceLabel = "device label " + random(); |
||||
|
|
||||
|
sideBarMenuView.goToDevicesPage(); |
||||
|
devicePage.openCreateDeviceView(); |
||||
|
devicePage.enterName(deviceName); |
||||
|
devicePage.enterLabel(deviceLabel); |
||||
|
devicePage.addBtnC().click(); |
||||
|
|
||||
|
assertIsDisplayed(devicePage.deviceLabelOnPage(deviceName)); |
||||
|
assertThat(devicePage.deviceLabelOnPage(deviceName).getText()).as("Label added correctly").isEqualTo(deviceLabel); |
||||
|
} |
||||
|
|
||||
|
@Test(groups = "smoke") |
||||
|
@Description("Add device with assignee on customer") |
||||
|
public void createDeviceWithAssignee() { |
||||
|
deviceName = ENTITY_NAME + random(); |
||||
|
String customer = "Customer A"; |
||||
|
|
||||
|
sideBarMenuView.goToDevicesPage(); |
||||
|
devicePage.openCreateDeviceView(); |
||||
|
devicePage.enterName(deviceName); |
||||
|
devicePage.assignOnCustomer(customer); |
||||
|
devicePage.addBtnC().click(); |
||||
|
|
||||
|
assertIsDisplayed(devicePage.deviceCustomerOnPage(deviceName)); |
||||
|
assertThat(devicePage.deviceCustomerOnPage(deviceName).getText()) |
||||
|
.as("Customer added correctly").isEqualTo(customer); |
||||
|
} |
||||
|
|
||||
|
@Test(groups = "smoke") |
||||
|
@Description("Go to devices documentation page") |
||||
|
public void documentation() { |
||||
|
String urlPath = "docs/user-guide/ui/devices/"; |
||||
|
|
||||
|
sideBarMenuView.goToDevicesPage(); |
||||
|
devicePage.entity("Thermostat T1").click(); |
||||
|
devicePage.goToHelpPage(); |
||||
|
|
||||
|
assertThat(urlContains(urlPath)).as("Redirected URL contains " + urlPath).isTrue(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,75 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2023 The Thingsboard Authors |
||||
|
* |
||||
|
* 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. |
||||
|
*/ |
||||
|
package org.thingsboard.server.msa.ui.tests.devicessmoke; |
||||
|
|
||||
|
import io.qameta.allure.Description; |
||||
|
import io.qameta.allure.Feature; |
||||
|
import org.testng.annotations.BeforeMethod; |
||||
|
import org.testng.annotations.Test; |
||||
|
import org.thingsboard.server.common.data.Device; |
||||
|
import org.thingsboard.server.msa.ui.utils.EntityPrototypes; |
||||
|
|
||||
|
import static org.thingsboard.server.msa.ui.utils.Const.ENTITY_NAME; |
||||
|
|
||||
|
@Feature("Delete device") |
||||
|
public class DeleteDeviceTest extends AbstractDeviceTest { |
||||
|
|
||||
|
@BeforeMethod |
||||
|
public void createDevice() { |
||||
|
Device device = testRestClient.postDevice("", EntityPrototypes.defaultDevicePrototype(ENTITY_NAME)); |
||||
|
deviceName = device.getName(); |
||||
|
} |
||||
|
|
||||
|
@Test(groups = "smoke") |
||||
|
@Description("Remove the device by clicking on the trash icon in the right side of device") |
||||
|
public void deleteDeviceByRightSideBtn() { |
||||
|
sideBarMenuView.goToDevicesPage(); |
||||
|
devicePage.deleteDeviceByRightSideBtn(deviceName); |
||||
|
devicePage.refreshBtn().click(); |
||||
|
|
||||
|
devicePage.assertEntityIsNotPresent(deviceName); |
||||
|
} |
||||
|
|
||||
|
@Test(groups = "smoke") |
||||
|
@Description("Remove device by mark in the checkbox and then click on the trash can icon in the menu that appears at the top") |
||||
|
public void deleteSelectedDevice() { |
||||
|
sideBarMenuView.goToDevicesPage(); |
||||
|
devicePage.deleteSelected(deviceName); |
||||
|
devicePage.refreshBtn().click(); |
||||
|
|
||||
|
devicePage.assertEntityIsNotPresent(deviceName); |
||||
|
} |
||||
|
|
||||
|
@Test(groups = "smoke") |
||||
|
@Description("Remove the device by clicking on the 'Delete device' btn in the entity view") |
||||
|
public void deleteDeviceFromDetailsTab() { |
||||
|
sideBarMenuView.goToDevicesPage(); |
||||
|
devicePage.entity(deviceName).click(); |
||||
|
devicePage.deleteDeviceFromDetailsTab(); |
||||
|
devicePage.refreshBtn(); |
||||
|
|
||||
|
devicePage.assertEntityIsNotPresent(deviceName); |
||||
|
} |
||||
|
|
||||
|
@Test(groups = "smoke") |
||||
|
@Description("Remove the device by clicking on the trash icon in the right side of device without refresh") |
||||
|
public void deleteDeviceWithoutRefresh() { |
||||
|
sideBarMenuView.goToDevicesPage(); |
||||
|
devicePage.deleteDeviceByRightSideBtn(deviceName); |
||||
|
|
||||
|
devicePage.assertEntityIsNotPresent(deviceName); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,84 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2023 The Thingsboard Authors |
||||
|
* |
||||
|
* 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. |
||||
|
*/ |
||||
|
package org.thingsboard.server.msa.ui.tests.devicessmoke; |
||||
|
|
||||
|
import io.qameta.allure.Description; |
||||
|
import io.qameta.allure.Feature; |
||||
|
import org.testng.annotations.AfterMethod; |
||||
|
import org.testng.annotations.BeforeMethod; |
||||
|
import org.testng.annotations.Test; |
||||
|
import org.thingsboard.server.common.data.Device; |
||||
|
import org.thingsboard.server.msa.ui.utils.EntityPrototypes; |
||||
|
|
||||
|
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
import static org.thingsboard.server.msa.ui.utils.Const.ENTITY_NAME; |
||||
|
|
||||
|
@Feature("Delete several devices") |
||||
|
public class DeleteSeveralDevicesTest extends AbstractDeviceTest { |
||||
|
|
||||
|
private String deviceName1; |
||||
|
private String deviceName2; |
||||
|
|
||||
|
@BeforeMethod |
||||
|
public void createDevices() { |
||||
|
Device device = testRestClient.postDevice("", EntityPrototypes.defaultDevicePrototype(ENTITY_NAME)); |
||||
|
Device device1 = testRestClient.postDevice("", EntityPrototypes.defaultDevicePrototype(ENTITY_NAME)); |
||||
|
deviceName1 = device.getName(); |
||||
|
deviceName2 = device1.getName(); |
||||
|
} |
||||
|
|
||||
|
@AfterMethod |
||||
|
public void deleteDevices() { |
||||
|
deleteDeviceByName(deviceName1); |
||||
|
deleteDeviceByName(deviceName2); |
||||
|
} |
||||
|
|
||||
|
@Test(groups = "smoke") |
||||
|
@Description("Remove several devices by mark in the checkbox and then click on the trash can icon in the menu " + |
||||
|
"that appears at the top") |
||||
|
public void deleteSeveralDevicesByTopBtn() { |
||||
|
sideBarMenuView.goToDevicesPage(); |
||||
|
devicePage.deleteSelected(2); |
||||
|
devicePage.refreshBtn().click(); |
||||
|
|
||||
|
devicePage.assertEntityIsNotPresent(deviceName1); |
||||
|
devicePage.assertEntityIsNotPresent(deviceName2); |
||||
|
} |
||||
|
|
||||
|
@Test(groups = "smoke") |
||||
|
@Description("Remove several devices by mark all the devices on the page by clicking in the topmost checkbox" + |
||||
|
" and then clicking on the trash icon in the menu that appears") |
||||
|
public void selectAllDevices() { |
||||
|
sideBarMenuView.goToDevicesPage(); |
||||
|
devicePage.selectAllCheckBox().click(); |
||||
|
devicePage.deleteSelectedBtn().click(); |
||||
|
|
||||
|
assertIsDisplayed(devicePage.warningPopUpTitle()); |
||||
|
assertThat(devicePage.warningPopUpTitle().getText()).as("Warning title contains true correct of selected devices") |
||||
|
.contains(String.valueOf(devicePage.markCheckbox().size())); |
||||
|
} |
||||
|
|
||||
|
@Test(groups = "smoke") |
||||
|
@Description("Remove several devices by mark in the checkbox and then click on the trash can icon in the menu " + |
||||
|
"that appears at the top without refresh") |
||||
|
public void deleteSeveralWithoutRefresh() { |
||||
|
sideBarMenuView.goToDevicesPage(); |
||||
|
devicePage.deleteSelected(2); |
||||
|
|
||||
|
devicePage.assertEntityIsNotPresent(deviceName1); |
||||
|
devicePage.assertEntityIsNotPresent(deviceName2); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,179 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2023 The Thingsboard Authors |
||||
|
* |
||||
|
* 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. |
||||
|
*/ |
||||
|
package org.thingsboard.server.msa.ui.tests.devicessmoke; |
||||
|
|
||||
|
import io.qameta.allure.Description; |
||||
|
import io.qameta.allure.Feature; |
||||
|
import org.testng.annotations.Test; |
||||
|
import org.thingsboard.server.msa.ui.utils.DataProviderCredential; |
||||
|
import org.thingsboard.server.msa.ui.utils.EntityPrototypes; |
||||
|
|
||||
|
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
import static org.thingsboard.server.msa.ui.base.AbstractBasePage.getRandomNumber; |
||||
|
import static org.thingsboard.server.msa.ui.utils.Const.EMPTY_DEVICE_MESSAGE; |
||||
|
import static org.thingsboard.server.msa.ui.utils.Const.ENTITY_NAME; |
||||
|
|
||||
|
@Feature("Edit device") |
||||
|
public class EditDeviceTest extends AbstractDeviceTest { |
||||
|
|
||||
|
@Test(groups = "smoke") |
||||
|
@Description("Change name by edit menu") |
||||
|
public void changeName() { |
||||
|
String newDeviceName = "Changed" + getRandomNumber(); |
||||
|
deviceName = testRestClient.postDevice("", EntityPrototypes.defaultDevicePrototype(ENTITY_NAME)).getName(); |
||||
|
|
||||
|
sideBarMenuView.goToDevicesPage(); |
||||
|
devicePage.entity(deviceName).click(); |
||||
|
devicePage.setHeaderName(); |
||||
|
String nameBefore = devicePage.getHeaderName(); |
||||
|
devicePage.editPencilBtn().click(); |
||||
|
devicePage.changeNameEditMenu(newDeviceName); |
||||
|
devicePage.doneBtnEditView().click(); |
||||
|
deviceName = newDeviceName; |
||||
|
devicePage.setHeaderName(); |
||||
|
String nameAfter = devicePage.getHeaderName(); |
||||
|
|
||||
|
assertThat(nameAfter).as("The name has changed").isNotEqualTo(nameBefore); |
||||
|
assertThat(nameAfter).as("The name has changed correctly").isEqualTo(newDeviceName); |
||||
|
} |
||||
|
|
||||
|
@Test(groups = "smoke") |
||||
|
@Description("Delete name and save") |
||||
|
public void deleteName() { |
||||
|
deviceName = testRestClient.postDevice("", EntityPrototypes.defaultDevicePrototype(ENTITY_NAME)).getName(); |
||||
|
|
||||
|
sideBarMenuView.goToDevicesPage(); |
||||
|
devicePage.entity(deviceName).click(); |
||||
|
devicePage.editPencilBtn().click(); |
||||
|
devicePage.changeNameEditMenu(""); |
||||
|
|
||||
|
assertIsDisable(devicePage.doneBtnEditViewVisible()); |
||||
|
} |
||||
|
|
||||
|
@Test(groups = "smoke") |
||||
|
@Description("Save only with space") |
||||
|
public void saveOnlyWithSpace() { |
||||
|
deviceName = testRestClient.postDevice("", EntityPrototypes.defaultDevicePrototype(ENTITY_NAME)).getName(); |
||||
|
|
||||
|
sideBarMenuView.goToDevicesPage(); |
||||
|
devicePage.entity(deviceName).click(); |
||||
|
devicePage.editPencilBtn().click(); |
||||
|
devicePage.changeNameEditMenu(" "); |
||||
|
devicePage.doneBtnEditView().click(); |
||||
|
|
||||
|
assertIsDisplayed(devicePage.warningMessage()); |
||||
|
assertThat(devicePage.warningMessage().getText()).as("Text of warning message").isEqualTo(EMPTY_DEVICE_MESSAGE); |
||||
|
} |
||||
|
|
||||
|
@Test(groups = "smoke", dataProviderClass = DataProviderCredential.class, dataProvider = "editMenuDescription") |
||||
|
@Description("Write the description and save the changes/Change the description and save the changes/Delete the description and save the changes") |
||||
|
public void editDescription(String description, String newDescription, String finalDescription) { |
||||
|
deviceName = testRestClient.postDevice("", EntityPrototypes.defaultDevicePrototype(ENTITY_NAME, description)).getName(); |
||||
|
|
||||
|
sideBarMenuView.goToDevicesPage(); |
||||
|
devicePage.entity(deviceName).click(); |
||||
|
devicePage.editPencilBtn().click(); |
||||
|
devicePage.descriptionEntityView().sendKeys(newDescription); |
||||
|
devicePage.doneBtnEditView().click(); |
||||
|
devicePage.setDescription(); |
||||
|
|
||||
|
assertThat(devicePage.getDescription()).as("The description changed correctly").isEqualTo(finalDescription); |
||||
|
} |
||||
|
|
||||
|
@Test(groups = "smoke", dataProviderClass = DataProviderCredential.class, dataProvider = "enable") |
||||
|
@Description("Enable gateway mode/Disable gateway") |
||||
|
public void isGateway(boolean isGateway) { |
||||
|
deviceName = testRestClient.postDevice("", EntityPrototypes.defaultDevicePrototype(ENTITY_NAME, isGateway)).getName(); |
||||
|
|
||||
|
sideBarMenuView.goToDevicesPage(); |
||||
|
devicePage.entity(deviceName).click(); |
||||
|
devicePage.editPencilBtn().click(); |
||||
|
devicePage.checkboxGatewayEdit().click(); |
||||
|
devicePage.doneBtnEditView().click(); |
||||
|
|
||||
|
if (isGateway) { |
||||
|
assertThat(devicePage.checkboxGatewayDetailsTab().getAttribute("class").contains("selected")) |
||||
|
.as("Gateway is disable").isFalse(); |
||||
|
} else { |
||||
|
assertThat(devicePage.checkboxGatewayDetailsTab().getAttribute("class").contains("selected")) |
||||
|
.as("Gateway is enable").isTrue(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Test(groups = "smoke", dataProviderClass = DataProviderCredential.class, dataProvider = "enable") |
||||
|
@Description("Enable overwrite activity time for connected/Disable overwrite activity time for connected") |
||||
|
public void isOverwriteActivityTimeForConnectedDevice(boolean isOverwriteActivityTimeForConnected) { |
||||
|
deviceName = testRestClient.postDevice("", |
||||
|
EntityPrototypes.defaultDevicePrototype(ENTITY_NAME, true, isOverwriteActivityTimeForConnected)).getName(); |
||||
|
|
||||
|
sideBarMenuView.goToDevicesPage(); |
||||
|
devicePage.entity(deviceName).click(); |
||||
|
devicePage.editPencilBtn().click(); |
||||
|
devicePage.checkboxOverwriteActivityTimeEdit().click(); |
||||
|
devicePage.doneBtnEditView().click(); |
||||
|
|
||||
|
if (isOverwriteActivityTimeForConnected) { |
||||
|
assertThat(devicePage.checkboxOverwriteActivityTimeDetails().getAttribute("class").contains("selected")) |
||||
|
.as("Overwrite activity time for connected is disable").isFalse(); |
||||
|
} else { |
||||
|
assertThat(devicePage.checkboxOverwriteActivityTimeDetails().getAttribute("class").contains("selected")) |
||||
|
.as("Overwrite activity time for connected is enable").isTrue(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Test(groups = "smoke") |
||||
|
@Description("Change device profile") |
||||
|
public void changeDeviceProfile() { |
||||
|
deviceName = testRestClient.postDevice("", EntityPrototypes.defaultDevicePrototype(ENTITY_NAME)).getName(); |
||||
|
|
||||
|
sideBarMenuView.goToDevicesPage(); |
||||
|
devicePage.entity(deviceName).click(); |
||||
|
devicePage.editPencilBtn().click(); |
||||
|
devicePage.changeDeviceProfile("DEFAULT"); |
||||
|
devicePage.doneBtnEditView().click(); |
||||
|
|
||||
|
assertIsDisplayed(devicePage.deviceProfileRedirectedBtn()); |
||||
|
assertThat(devicePage.deviceProfileRedirectedBtn().getText()).as("Profile changed correctly").isEqualTo("DEFAULT"); |
||||
|
} |
||||
|
|
||||
|
@Test(groups = "smoke") |
||||
|
@Description("Save without device profile") |
||||
|
public void saveWithoutDeviceProfile() { |
||||
|
deviceName = testRestClient.postDevice("", EntityPrototypes.defaultDevicePrototype(ENTITY_NAME)).getName(); |
||||
|
|
||||
|
sideBarMenuView.goToDevicesPage(); |
||||
|
devicePage.entity(deviceName).click(); |
||||
|
devicePage.editPencilBtn().click(); |
||||
|
devicePage.clearProfileFieldBtn().click(); |
||||
|
|
||||
|
assertIsDisable(devicePage.doneBtnEditViewVisible()); |
||||
|
} |
||||
|
|
||||
|
@Test(groups = "smoke", dataProviderClass = DataProviderCredential.class, dataProvider = "editDeviceLabel") |
||||
|
@Description("Write the label and save the changes/Change the label and save the changes/Delete the label and save the changes") |
||||
|
public void editLabel(String label, String newLabel, String finalLabel) { |
||||
|
deviceName = testRestClient.postDevice("", EntityPrototypes.defaultDevicePrototype(ENTITY_NAME, "", label)).getName(); |
||||
|
|
||||
|
sideBarMenuView.goToDevicesPage(); |
||||
|
devicePage.entity(deviceName).click(); |
||||
|
devicePage.editPencilBtn().click(); |
||||
|
devicePage.deviceLabelEditField().sendKeys(newLabel); |
||||
|
devicePage.doneBtnEditView().click(); |
||||
|
devicePage.setLabel(); |
||||
|
|
||||
|
assertThat(devicePage.getLabel()).as("The label changed correctly").isEqualTo(finalLabel); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,35 @@ |
|||||
|
<?xml version="1.0" encoding="ISO-8859-1"?> |
||||
|
<!-- |
||||
|
|
||||
|
Copyright © 2016-2023 The Thingsboard Authors |
||||
|
|
||||
|
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. |
||||
|
|
||||
|
--> |
||||
|
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" > |
||||
|
|
||||
|
<suite name="Devices Smoke Tests"> |
||||
|
<listeners> |
||||
|
<listener class-name="org.thingsboard.server.msa.ui.listeners.RetryTestListener"/> |
||||
|
</listeners> |
||||
|
<test name="Devices ui smoke tests"> |
||||
|
<groups> |
||||
|
<run> |
||||
|
<exclude name="broken"/> |
||||
|
</run> |
||||
|
</groups> |
||||
|
<packages> |
||||
|
<package name="org.thingsboard.server.msa.ui.tests.devicessmoke"/> |
||||
|
</packages> |
||||
|
</test> |
||||
|
</suite> |
||||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue